Fusionar listas con la API de transmisión

3 minutos de lectura

avatar de usuario
mat_boy

tengo la siguiente situacion

Map<Key, ListContainer> map; 

public class ListContainer {
  List<AClass> lst;
}

Tengo que fusionar todas las listas. lst desde el ListContainer objetos de un Map mapa.

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

¿Alguna idea de cómo, usando la API de flujo de Java 8?

  • ¿Puede proporcionar un ejemplo de lo que quiere decir con la fusión? Di que tu mapa es {a: [1,2], b[3,4]}quieres encadenarlos, como [1,2,3,4]o hacer una lista de listas, [[1,2],[3,4]]o comprimirlos [[1,3],[2,4]]? Además, eres consciente de que un Mapa no tiene orden, ¿verdad?

    – tobias_k

    16 de abril de 2014 a las 14:56


  • @tobias_k quiero que el resultado sea [1,2,3,4]sin clasificar!

    – mat_boy

    16 de abril de 2014 a las 15:06


  • Si ListContainer solo envuelve un List<T> entonces puedes reemplazar Map<Key, ListContainer> con Map<Key, List<T>>

    – El águila pirotécnica

    29 de diciembre de 2016 a las 13:52


avatar de usuario
Pardo rojizo

pienso flatMap() es lo que buscas

Por ejemplo:

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

  • ? ¿Por qué se eliminaron los comentarios que explicaban por qué? .flatMap(Collection::stream) no es posible aquí?

    – Puce

    1 de noviembre de 2016 a las 1:33


  • @Puce buena pregunta, sin embargo, es posible: si ListContainer está encapsulado (es decir, tiene un getter para lst), se puede descomponer .flatMap(->) dentro .map(ListContainer::getLst) .flatMap(Collection::stream)

    – TWiStErRob

    9 de noviembre de 2016 a las 10:48


  • @TWiStErRob Sí, eso es lo que escribí en mi comentario original. ¿Por qué se eliminó?

    – Puce

    9 de noviembre de 2016 a las 11:35

  • @Puce una nota en tu respuesta explicando por qué .flatMap(Collection::stream) No es posible sería mejor, creo. Debería ser más permanente.

    – SQB

    21 de septiembre de 2018 a las 10:05

  • @Alex sí, esta es una manera resp. .map(listContainer -> listContainer.lst).filter(Objects::nonNull).flatMap(Collection::stream)

    – Puce

    4 sep 2019 a las 11:19

Alternativa: Stream.concat()

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

  • más 1 aunque no responde la pregunta, responde el título de la pregunta

    – Tony BenBrahim

    16 de julio de 2017 a las 3:45


avatar de usuario
azul

Ya respondí anteriormente, pero aquí hay otro enfoque que podría tomar. No puedo encontrar la publicación original de la que adapté esto, pero aquí está el código por el bien de su pregunta. Como se señaló anteriormente, la función flatMap() es lo que estaría buscando utilizar con Java 8. Puede incluirla en una clase de utilidad y simplemente llamar a “RandomUtils.combine (list1, list2, …);” y obtendría una sola lista con todos los valores. Solo tenga cuidado con el comodín: puede cambiar esto si desea un método menos genérico. También puede modificarlo para conjuntos: solo debe tener cuidado al usar flatMap() en conjuntos para evitar la pérdida de datos de los métodos equals/hashCode debido a la naturaleza de la interfaz de conjunto.

Editar: si usa un método genérico como este para la interfaz Set, y usa Lombok, asegúrese de comprender cómo maneja Lombok la generación de códigos iguales/hashCode.

  /**
    * 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());
   }

En Java 8 podemos usar la secuencia List1.stream().collect(Collectors.toList()).addAll(List2); Otra opción List1.addAll(List2)

Para fusionar varias listas u otros tipos de colecciones en una sola, puede utilizar este enfoque:

Stream.of(list1.stream(), list2.stream(), someSet.stream(), otherCollection.stream())
    .flatMap(Function.identity())
    .collect(Collectors.toList());

¿Ha sido útil esta solución?