Java 8: scal listy ze strumieniowym API


80

Mam następującą sytuację

Map<Key, ListContainer> map; 

public class ListContainer{
  List<AClass> lst;
}

Muszę scalić wszystkie listy lstz ListContainerobiektów z Mapmapy.

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

Masz jakiś pomysł, jak, używając strumieniowego API Java 8?


Czy możesz podać przykład, co masz na myśli mówiąc o scalaniu? Powiedzmy, że Twoja mapa jest taka {a: [1,2], b[3,4]}, czy chcesz je [1,2,3,4]połączyć w łańcuch, polubić , utworzyć listę list [[1,2],[3,4]]lub spakować je [[1,3],[2,4]]? Wiesz też, że mapa nie ma porządku, prawda?
tobias_k

@tobias_k Chcę, aby wynik był [1,2,3,4]nieposortowany!
mat_boy,

Jeśli ListContainertylko owija List<T>następnie można wymienić Map<Key, ListContainer>zMap<Key, List<T>>
ThePyroEagle

Odpowiedzi:


169

Myślę, że flatMap()właśnie tego szukasz.

Na przykład:

 List<AClass> allTheObjects = map.values()
         .stream()
         .flatMap(listContainer -> listContainer.lst.stream())
         .collect(Collectors.toList());

2
? Dlaczego usunięto komentarze wyjaśniające, dlaczego .flatMap(Collection::stream)nie jest to możliwe?
Puce

@Puść dobre pytanie, jednak jest to możliwe: jeśli ListContainerjest hermetyzowane (tj. Ma getter lst), możesz rozłożyć .flatMap(->)na.map(ListContainer::getLst) .flatMap(Collection::stream)
TWiStErRob

3
@TWiStErRob Tak, to właśnie napisałem w moim pierwotnym komentarzu. Dlaczego został usunięty?
Puce,

@ Dodaj notatkę w swojej odpowiedzi wyjaśniającą, dlaczego .flatMap(Collection::stream)nie jest to możliwe, byłoby lepiej, jak sądzę. Powinien być bardziej trwały.
SQB,

1
@Alex tak, to jest w jedną stronę resp. .map(listContainer -> listContainer.lst).filter(Objects::nonNull).flatMap(Collection::stream)
Puce

55

Alternatywa: Stream.concat ()

Stream.concat(map.values().stream(), listContainer.lst.stream())
                             .collect(Collectors.toList()

2
plus 1 mimo, że nie odpowiada na pytanie, odpowiada tytułowi pytania
Tony BenBrahim

2

W Javie 8 możemy użyć strumienia List1.stream (). Collect (Collectors.toList ()). AddAll (List2); Inna opcja List1.addAll (List2)


1

Odpowiedziałem już powyżej, ale oto inne podejście, które możesz zastosować. Nie mogę znaleźć oryginalnego posta, z którego to dostosowałem, ale oto kod na potrzeby twojego pytania. Jak wspomniano powyżej, funkcja flatMap () jest tym, czego chciałbyś użyć w Javie 8. Możesz wrzucić ją do klasy narzędziowej i po prostu wywołać "RandomUtils.combine (list1, list2, ...);" i otrzymasz pojedynczą listę ze wszystkimi wartościami. Uważaj tylko na symbole wieloznaczne - możesz to zmienić, jeśli chcesz mniej ogólną metodę. Możesz również zmodyfikować go dla Setów - po prostu musisz uważać podczas używania flatMap () na Setach, aby uniknąć utraty danych z metod equals / hashCode ze względu na naturę interfejsu 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());
   }
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.