Карта групп потоков Java по свойству ее ключа

#java #java-stream

Вопрос:

Допустим, есть следующий класс

 class A {
  B b
}
 

И у меня есть инициалы Map<A, List<C>> .
Как я могу сгруппировать A по b и получить Map<B, Map<A, List<C>>> ?

Комментарии:

1. Это было бы что-то вроде collect(toMap(A::getB, Function.identity())) .

2. Какая версия Java?

3. Пожалуйста, проясните вашу конкретную проблему или предоставьте дополнительные сведения, чтобы точно указать, что вам нужно. Поскольку это написано в настоящее время, трудно точно сказать, о чем вы просите.

Ответ №1:

Я не уверен Map<B, Map<A, List<C>>> , что это имеет смысл в качестве вывода. Но вы можете попробовать что-то вроде:

 myAMap.keySet().stream().reduce(new HashMap<B, List<A>>(), (map, key) -> {

    if(map.get(key.b) == null) map.set(key.b, [key]);
    else if(map.get(key.b) != null) map.set(key.b, map.get(key.b).add(key));

    return map;

}), 

 

Ответ №2:

Вы можете сделать это с помощью Java 9 (требуется для entry() и flatMapping() ):

 Map<B, Map<A, List<C>>> result = map.entrySet()
        .stream()
        .map(e -> Map.entry(e.getKey().b, Map.entry(e.getKey(), e.getValue().stream())))
        .collect(groupingBy(Entry::getKey,
                mapping(Entry::getValue,
                        groupingBy(Entry::getKey,
                                flatMapping(Entry::getValue, toList())))));
 

Демо-версия Ideon

Это не очень приятное чтение, я знаю. Может быть, вы сможете добиться большего успеха с StreamEx.

Ответ №3:

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

Сначала создайте экземпляр целевой карты.

 Map<B, Map<A, List<C>>> result = new HashMap<>();
 
  • выполните итерацию по входному набору исходной карты.
  • если нужного ключа нет, создайте запись с a HashMap , в противном случае используйте существующий HashMap .
  • затем, если существующий ключ отсутствует, поместите его во внутреннюю карту вместе с исходным значением.
 for (Map.Entry<A, List<C>> e : sourceMap.entrySet()) {
    result.computeIfAbsent(e.getKey().b, v->new HashMap<>())
            .putIfAbsent(e.getKey(), e.getValue());
}