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....    
}

Будь-яка ідея, як, використовуючи Java 8 потік API?


Чи можете ви навести приклад, що ви маєте на увазі під об’єднанням? Скажімо, ваша карта така {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лише обгортання a, 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());

2
? Чому були видалені коментарі, які пояснювали, чому .flatMap(Collection::stream)тут не можна?
Puce

@Puce гарне запитання, однак це можливо: якщо ListContainerінкапсульовано (тобто має геттер для lst), ви можете розкластись .flatMap(->)на нього.map(ListContainer::getLst) .flatMap(Collection::stream)
TWiStErRob

3
@TWiStErRob Так, саме про це я писав у своєму оригінальному коментарі. Чому його видалили?
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, хоча він і не відповідає на питання, він відповідає на назву питання
Tony BenBrahim

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());
   }
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.