Необходимо сделать карту & lt; K, карту & lt; V, список & gt; & gt; & gt; & gt; & gt; & gt; & gt; [Дубликат]

php7:

sudo a2enmod proxy_fcgi setenvif
sudo a2enconf php7.0-fpm
sudo service apache2 restart
37
задан Mital Pritmani 5 February 2015 в 12:30
поделиться

6 ответов

Метод groupingBy имеет первый параметр Function<T,K> где:

@param <T> тип входных элементов

@param <K> ] тип ключей

Если мы заменим лямбда на анонимный класс в вашем коде, мы увидим что-то вроде этого:

people.stream().collect(Collectors.groupingBy(new Function<Person, int>() {
            @Override
            public int apply(Person person) {
                return person.getAge();
            }
        }));

Теперь измените выходной параметр <K>. В этом случае, например, я использовал парный класс из org.apache.commons.lang3.tuple для группировки по имени и возрасту, но вы можете создать свой собственный класс для фильтрации групп по мере необходимости.

people.stream().collect(Collectors.groupingBy(new Function<Person, Pair<Integer, String>>() {
                @Override
                public YourFilter apply(Person person) {
                    return Pair.of(person.getAge(), person.getName());
                }
            }));

Наконец, после замены с помощью лямбда-кода код выглядит следующим образом:

Map<Pair<Integer,String>, List<Person>> peopleByAgeAndName = people.collect(Collectors.groupingBy(p -> Pair.of(person.getAge(), person.getName()), Collectors.mapping((Person p) -> p, toList())));
1
ответ дан Andrei Smirnov 21 August 2018 в 09:46
поделиться

Привет Вы можете просто объединить ваши groupingByKey, такие как

Map<String, List<Person>> peopleBySomeKey = people
                .collect(Collectors.groupingBy(p -> getGroupingByKey(p), Collectors.mapping((Person p) -> p, toList())));



//write getGroupingByKey() function
private String getGroupingByKey(Person p){
return p.getAge()+"-"+p.getName();
}
3
ответ дан Anptk 21 August 2018 в 09:46
поделиться

Мне нужно было сделать отчет для фирмы общественного питания, которая предлагает обеды для разных клиентов. Другими словами, кейтеринг может иметь или больше фирм, которые принимают заказы от общественного питания, и он должен знать, сколько обедов он должен производить каждый день для всех своих клиентов!

Чтобы заметить, я не использовал сортировку, чтобы не усложнять этот пример.

Это мой код:

@Test
public void test_2() throws Exception {
    Firm catering = DS.firm().get(1);
    LocalDateTime ldtFrom = LocalDateTime.of(2017, Month.JANUARY, 1, 0, 0);
    LocalDateTime ldtTo = LocalDateTime.of(2017, Month.MAY, 2, 0, 0);
    Date dFrom = Date.from(ldtFrom.atZone(ZoneId.systemDefault()).toInstant());
    Date dTo = Date.from(ldtTo.atZone(ZoneId.systemDefault()).toInstant());

    List<PersonOrders> LON = DS.firm().getAllOrders(catering, dFrom, dTo, false);
    Map<Object, Long> M = LON.stream().collect(
            Collectors.groupingBy(p
                    -> Arrays.asList(p.getDatum(), p.getPerson().getIdfirm(), p.getIdProduct()),
                    Collectors.counting()));

    for (Map.Entry<Object, Long> e : M.entrySet()) {
        Object key = e.getKey();
        Long value = e.getValue();
        System.err.println(String.format("Client firm :%s, total: %d", key, value));
    }
}
0
ответ дан dobrivoje 21 August 2018 в 09:46
поделиться

Посмотрите на код:

Вы можете просто создать функцию и позволить ей выполнять работу для вас, своего рода функциональный стиль!

Function<Person, List<Object>> compositeKey = personRecord ->
    Arrays.<Object>asList(personRecord.getName(), personRecord.getAge());

Теперь вы можете использовать это как карта:

Map<Object, List<Person>> map =
people.collect(Collectors.groupingBy(compositeKey, Collectors.toList()));

Приветствия!

15
ответ дан Farhan S. 21 August 2018 в 09:46
поделиться

Определите класс для определения ключа в вашей группе.

class KeyObj {

    ArrayList<Object> keys;

    public KeyObj( Object... objs ) {
        keys = new ArrayList<Object>();

        for (int i = 0; i < objs.length; i++) {
            keys.add( objs[i] );
        }
    }

    // Add appropriate isEqual() ... you IDE should generate this

}

Теперь в вашем коде

peopleByManyParams = people
            .collect(Collectors.groupingBy(p -> new KeyObj( p.age, p.other1, p.other2 ), Collectors.mapping((Person p) -> p, toList())));
1
ответ дан Sarvesh Kumar Singh 21 August 2018 в 09:46
поделиться
  • 1
    Это просто заново изобретает Ararys.asList() --- что является BTW прекрасным выбором для случая OP. – Marko Topolnik 5 February 2015 в 12:57
  • 2
    А также аналогично примеру Pair, упомянутому в другом примере, но без ограничения аргумента. – Benny Bottema 9 July 2016 в 12:21
  • 3
    Также вам нужно сделать это неизменным. (и вычислить hashCode) один раз) – RobAu 30 May 2017 в 09:58

У вас есть несколько вариантов. Самое простое - связать своих коллекционеров:

Map<String, Map<Integer, List<Person>>> map = people
    .collect(Collectors.groupingBy(Person::getName,
        Collectors.groupingBy(Person::getAge));

. Затем, чтобы получить список 18-летних людей по имени Фред, вы будете использовать:

map.get("Fred").get(18);

Второй вариант - определить класс, представляющий группировку. Это может быть внутри Person:

class Person {
    public static class NameAge {
        public NameAge(String name, int age) {
            ...
        }

        // must implement equals and hash function
    }

    public NameAge getNameAge() {
        return new NameAge(name, age);
    }
}

Затем вы можете использовать:

Map<NameAge, List<Person>> map = people.collect(Collectors.groupingBy(Person::getNameAge));

и искать с помощью

map.get(new NameAge("Fred", 18));

Наконец, если вы этого не сделаете хотите реализовать свой собственный групповой класс, тогда многие из фреймворков Java вокруг имеют класс pair, предназначенный именно для такого типа вещей. Например: apache commons pair Если вы используете одну из этих библиотек, вы можете сделать ключ к карте парой имен и возраста:

Map<Pair<String, Integer>, List<Person>> map =
    people.collect(Collectors.groupingBy(p -> Pair.of(p.getName(), p.getAge())));

и получить с помощью :

map.get(Pair.of("Fred", 18));

Лично мне очень не нравятся эти кортежные библиотеки. Они, кажется, являются полной противоположностью хорошему дизайну OO: они скрывают намерение, а не обнажают его.

Сказав, что вы можете объединить два вторых варианта, определив свой собственный класс группировки, но реализуя его, просто расширив Pair, что значительно облегчает вам работу по определению equals и т. д. и скрывает использование кортежа как удобную деталь реализации, как и любую другую коллекцию.

Удачи.

83
ответ дан sprinter 21 August 2018 в 09:46
поделиться
  • 1
    Function<T,U> также скрывает намерение в этом смысле, но вы не увидите никого, кто объявит свой собственный функциональный интерфейс для каждого шага отображения; намерение уже существует в лямбда-теле. То же самое с кортежами: они великолепны как типы клея между компонентами API. BTW Scala case classes являются ИМХО большой победой в плане как лаконичности, так и намерения. – Marko Topolnik 6 February 2015 в 14:53
  • 2
    Да, я вижу вашу мысль. Я думаю (как всегда), это зависит от того, как они используются. Пример, который я привел выше - использование пары в качестве ключа Карты - является хорошим примером того, как не делать этого. Я не слишком хорошо знаком с Scala - мне придется начинать изучать ее, когда я слышу хорошие вещи. – sprinter 6 February 2015 в 14:59
  • 3
    Представьте, что вы можете объявить NameAge как однострочный: case class NameAge { val name: String; val age: Int } --- и вы получите equals, hashCode и toString! – Marko Topolnik 6 February 2015 в 15:02
  • 4
    Ницца - еще один элемент, надавленный на мою очередь «должен сделать». К сожалению, это FIFO! – sprinter 6 February 2015 в 15:04
  • 5
    кажется таким легким, когда вы знаете решение. Благодаря! – IcedDante 29 October 2015 в 22:14
Другие вопросы по тегам:

Похожие вопросы: