Java 8: Cómo convertir un mapa en una lista

En este tutorial, veremos cómo convertir un mapa de Java en una lista de Java con Streams, Stream.map(), Stream.filter(), Stream.sorted() y Stream.flatMap(), con ejemplos .

Introducción

Una implementación de Java Map es una colección que asigna claves a valores. Cada Entrada de mapa contiene pares clave/valor, y cada clave está asociada con exactamente un valor. Las claves son únicas, por lo que no es posible realizar duplicados.

Una implementación común de la interfaz Map es un HashMap:

1
2
3
4
5
6
Map<Integer, String> students = new HashMap<>();
students.put(132, "James");
students.put(256, "Amy");
students.put(115, "Young");

System.out.println("Print Map: " + students);

Hemos creado un mapa simple de estudiantes (Strings) y sus respectivas ID:

1
Print Map: {256=Amy, 115=Young, 123=James}

Una implementación de Java List es una colección que almacena secuencialmente referencias a elementos. Cada elemento tiene un índice y se identifica de forma única por él:

1
2
3
List<String> list = new ArrayList<>(Arrays.asList("James", "Amy", "Young"));
System.out.println(list);
System.out.println(String.format("Third element: %s", list.get(2));
1
2
[James, Amy, Young]
Third element: Young

La diferencia clave es: Mapas tienen dos dimensiones, mientras que Listas tienen una dimensión.

Sin embargo, esto no nos impide convertir Mapas en Listas a través de varios enfoques. En este tutorial, veremos cómo convertir un mapa de Java en una lista de Java:

Convertir mapa en lista de Map.Entry<K,V>

Java 8 nos presentó la Stream API, que se concibió como un paso hacia la integración de la Programación funcional en Java para hacer que las tareas voluminosas y laboriosas fueran más legibles y simples. Los flujos funcionan maravillosamente con las colecciones y pueden ayudarnos a convertir un mapa en una lista.

La forma más sencilla de conservar las asignaciones clave-valor de un Mapa, mientras se sigue convirtiendo en una Lista sería transmitir() las entradas, que consisten en los pares clave-valor.

El método entrySet() devuelve un Conjunto de elementos Map.Entry<K,V>, que se pueden convertir fácilmente en una Lista, dado que ambos implementan Colección:

1
2
3
4
5
List<Map.Entry<Integer, String>> singleList = students.entrySet()
        .stream()
        .collect(Collectors.toList());
        
System.out.println("Single list: " + singleList);

Esto resulta en:

1
Single list: [256=Amy, 115=Young, 132=James]

Dado que los Streams no son colecciones en sí mismos, simplemente transmiten datos de una Colección, los Coleccionistas se utilizan para recopilar el resultado de las operaciones de un Stream en una Colección. Uno de los Collectors que podemos usar es Collectors.toList(), que recopila elementos en una Lista.

Convertir mapa en lista usando dos listas

Dado que los Mapas son colecciones bidimensionales, mientras que las Listas son colecciones unidimensionales, el otro enfoque sería convertir un ‘Mapa’ en dos ‘Listas’, una de las cuales contendrá las *claves del Mapa. *, mientras que el otro contendría los valores del mapa.

Afortunadamente, podemos acceder fácilmente a las claves y valores de un mapa a través de los métodos keySet() y values().

El método keySet() devuelve un Set de todas las claves, lo cual es de esperar, ya que las claves tienen que ser únicas. Debido a la flexibilidad de las Colecciones de Java, podemos crear una Lista a partir de un Conjunto simplemente pasando un Conjunto al constructor de una Lista.

El método values() devuelve una Colección de los valores en el mapa y, naturalmente, dado que una Lista implementa la Colección, la conversión es tan fácil como pasarla en el constructor de la Lista:

1
2
3
4
5
List<Integer> keyList = new ArrayList(students.keySet());
List<String> valueList = new ArrayList(students.values());

System.out.println("Key List: " + keyList);
System.out.println("Value List: " + valueList);

Esto resulta en:

1
2
Key List: [256, 115, 132]
Value List: [Amy, Young, James]

Convertir mapa en lista con Collectors.toList() y Stream.map()

Vamos a ‘vaporizar()’ las claves y valores de un ‘Mapa’, y luego ‘recolectarlos()’ en una ‘Lista’:

1
2
3
4
5
List<Integer> keyList = students.keySet().stream().collect(Collectors.toList());
System.out.println("Key list: " + keyList);

List<String> valueList = students.values().stream().collect(Collectors.toList());
System.out.println("Value list: " + valueList);

Esto resulta en:

1
2
Key list: [256, 115, 132]
Value list: [Amy, Young, James]

Este enfoque tiene la ventaja de permitirnos realizar varias otras operaciones o transformaciones en los datos antes de recopilarlos. Por ejemplo, sabiendo que estamos trabajando con Strings, podríamos adjuntar una función anónima (expresión lambda). Por ejemplo, podríamos invertir los bytes de cada ‘Entero’ (clave) y poner en minúsculas cada ‘Cadena’ (valor) antes de recopilarlos en una ‘Lista’:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
List<Integer> keyList = students.keySet()
        .stream()
        .map(Integer::reverseBytes)
        .collect(Collectors.toList());
        
System.out.println("Key list: " + keyList);

List<String> valueList = students.values()
        .stream()
        .map(String::toLowerCase)
        .collect(Collectors.toList());
        
System.out.println("Value list: " + valueList);

Nota: El método map() devuelve un nuevo Stream en el que se aplica la expresión Lambda proporcionada a cada elemento. Si desea leer más sobre el método Stream.map(), lea nuestro Java 8 - Stream.mapa() tutorial.

Ejecutar este código transforma cada valor en los flujos antes de devolverlos como listas:

1
2
Key list: [65536, 1929379840, -2080374784]
Value list: [amy, young, james]

También podemos usar el método Collectors.toCollection(), que nos permite elegir la implementación particular de List:

1
2
3
4
5
6
7
8
9
List<Integer> keyList = students.keySet()
        .stream()
        .collect(Collectors.toCollection(ArrayList::new));
List<String> valueList = students.values()
        .stream()
        .collect(Collectors.toCollection(ArrayList::new));

System.out.println("Key list: " + keyList);
System.out.println("Value list: " + valueList);

Esto resulta en:

1
2
Key list: [256, 115, 132]
Value list: [Amy, Young, James]

Convertir mapa en lista con Stream.filter() y Stream.sorted()

No solo estamos limitados a asignar valores a sus transformaciones con Streams. También podemos filtrar y ordenar colecciones, de modo que las listas que estamos creando tengan ciertos elementos seleccionados. Esto se logra fácilmente a través de sorted() y filter():

1
2
3
4
5
6
List<String> sortedValueList = students.values()
        .stream()
        .sorted()
        .collect(Collectors.toList());
        
System.out.println("Sorted Values: " + sortedValueList);

Después de ordenar los valores obtenemos el siguiente resultado:

1
Sorted Values: [Amy, James, Young]

También podemos pasar un comparador personalizado al método sorted():

1
2
3
4
5
6
List<String> sortedValueList = students.values()
        .stream()
        .filter(value-> value.startsWith("J"))
        .collect(Collectors.toList());
        
System.out.println("Sorted Values: " + sortedValueList);

Lo que resulta en:

1
Sorted Values: [James]

Si desea leer más sobre el método sorted() y cómo usarlo, tenemos una guía sobre [Cómo ordenar una lista con Stream.sorted()](/java-8-como -ordenar-la-lista-con-flujo-ordenado/).

Convertir mapa en lista con Stream.flatMap()

El flatMap() es otro método Stream, usado para aplanar un flujo bidimensional de una colección en un flujo unidimensional de una colección. Mientras Stream.map() nos proporciona un mapeo A->B, el método Stream.flatMap() nos proporciona un mapeo A -> Stream<B>, que es luego aplanado en un solo Stream nuevamente.

Si tenemos un Stream bidimensional o un Stream de un Stream, podemos aplanarlo en uno solo. Esto es conceptualmente muy similar a lo que estamos tratando de hacer: convertir una colección 2D en una colección 1D. Vamos a mezclar un poco las cosas creando un Map<K,V> donde las claves son del tipo Integer mientras que los valores son del tipo List<String>:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
Map<Integer, List<String>> newMap = new HashMap<>();

List<String> firstName = new ArrayList();
firstName.add(0, "Jon");
firstName.add(1, "Johnson");
List<String> secondName = new ArrayList();
secondName.add(0, "Peter");
secondName.add(1, "Malone");

// Insert elements into the Map
newMap.put(1, firstName);
newMap.put(2, secondName);

List<String> valueList = newMap.values()
        .stream()
        // Aforementioned A -> Stream<B> mapping
        .flatMap(e -> e.stream())
        .collect(Collectors.toList());

System.out.println(valueList);

Esto resulta en:

1
[Jon, Johnson, Peter, Malone]

Conclusión

En este tutorial, hemos visto cómo convertir Map to List en Java de varias maneras con o sin usar la API de flujo de Java 8.

Licensed under CC BY-NC-SA 4.0