Java 8: объединить списки с потоковым API

80

У меня следующая ситуация

Map<Key, ListContainer> map; 

public class ListContainer{
  List<AClass> lst;
}

Я должен объединить все списки lstиз ListContainerобъектов из Mapкарты.

public static void main(String args[]){
   List<AClass> alltheObjectsAClass = map.values().stream(). // continue....    
}

Есть идеи, как с помощью потокового API Java 8?

mat_boy
источник
Вы можете привести пример того, что вы имеете в виду под слиянием? Скажем, ваша карта: {a: [1,2], b[3,4]}вы хотите объединить их в цепочку [1,2,3,4], поставить лайк или составить список списков [[1,2],[3,4]], или заархивировать их [[1,3],[2,4]]? Кроме того, вы знаете, что на карте нет порядка, не так ли?
tobias_k
@tobias_k Я хочу, чтобы результат был [1,2,3,4]несортированным!
mat_boy
Если ListContainerтолько оборачивает, List<T>то вы можете заменить Map<Key, ListContainer>наMap<Key, List<T>>
ThePyroEagle

Ответы:

169

Я думаю, flatMap()это то, что вы ищете.

Например:

 List<AClass> allTheObjects = map.values()
         .stream()
         .flatMap(listContainer -> listContainer.lst.stream())
         .collect(Collectors.toList());
Puce
источник
2
? Почему были удалены комментарии, объясняющие, почему .flatMap(Collection::stream)здесь невозможно?
Puce
@Puce - хороший вопрос, но вполне возможно: если ListContainerон инкапсулирован (т.е. имеет геттер для lst), вы можете разложить его .flatMap(->)на.map(ListContainer::getLst) .flatMap(Collection::stream)
TWiStErRob
3
@TWiStErRob Да, это то, что я написал в своем первоначальном комментарии. Почему его удалили?
Puce
@Puce примечание в своем ответе, объясняющее, почему .flatMap(Collection::stream)это невозможно, было бы лучше, я думаю. Должен быть более постоянным.
SQB
1
@Alex да, это в одну сторону соответственно. .map(listContainer -> listContainer.lst).filter(Objects::nonNull).flatMap(Collection::stream)
Puce
55

Альтернатива: Stream.concat ()

Stream.concat(map.values().stream(), listContainer.lst.stream())
                             .collect(Collectors.toList()
Ходящий по небу
источник
2
плюс 1, хотя он не отвечает на вопрос, он отвечает на заголовок вопроса
Тони Бен-Брахим
2

В Java 8 мы можем использовать поток List1.stream (). Collect (Collectors.toList ()). AddAll (List2); Другой вариант List1.addAll (List2)

Концерн
источник
1

Уже ответил выше, но вот другой подход, который вы можете использовать. Я не могу найти исходный пост, из которого я адаптировал его, но вот код для вашего вопроса. Как отмечалось выше, функция flatMap () - это то, что вы хотели бы использовать с Java 8. Вы можете добавить ее в служебный класс и просто вызвать "RandomUtils.combine (list1, list2, ...);" и вы получите единый список со всеми значениями. Просто будьте осторожны с подстановочным знаком - вы можете изменить его, если хотите менее общий метод. Вы также можете изменить его для наборов - вам просто нужно позаботиться об использовании flatMap () для наборов, чтобы избежать потери данных из методов equals / hashCode из-за природы интерфейса Set.

  /**
    * Combines multiple lists into a single list containing all elements of
    * every list.
    * 
    * @param <T> - The type of the lists.
    * @param lists - The group of List implementations to combine
    * @return a single List<?> containing all elements of the passed in lists.
    */
   public static <T> List<?> combine(final List<?>... lists) {
      return Stream.of(lists).flatMap(List::stream).collect(Collectors.toList());
   }
блау
источник