recorrer ordenado definicion java java-8 java-stream

ordenado - mapping en java



Usando flujos, ¿cómo puedo mapear los valores en un HashMap? (3)

Dado un Map<String, Person> donde la Persona tiene un método String getName() (etc.), ¿cómo puedo convertir el Map<String, Person> en un Map<String, String> donde la String se obtiene de la Person::getName() llama? Person::getName() ?

Pre-Java 8 yo usaría

Map<String, String> byNameMap = new HashMap<>(); for (Map.Entry<String, Person> person : people.entrySet()) { byNameMap.put(person.getKey(), person.getValue().getName()); }

pero me gustaría hacerlo usando arroyos y lambdas.

No puedo ver cómo hacer esto en un estilo funcional: Map / HashMap no implementa Stream .

people.entrySet() devuelve un Set<Entry<String, Person>> que puedo transmitir, pero ¿cómo puedo agregar una nueva Entry<String, String> al mapa de destino?


Con Java 8 puedes hacer:

Map<String, String> byNameMap = new HashMap<>(); people.forEach((k, v) -> byNameMap.put(k, v.getName());

Aunque sería mejor utilizar los Maps.transformValues de Guava, que envuelven el Map original y realiza la conversión cuando se get , lo que significa que solo paga el costo de la conversión cuando realmente consume el valor.

El uso de guayaba se vería así:

Map<String, String> byNameMap = Maps.transformValues(people, Person::getName);

EDITAR:

Siguiendo el comentario de @ Eelco (y para completar), la conversión a un mapa es mejor con Collectors.toMap así:

Map<String, String> byNameMap = people.entrySet() .stream() .collect(Collectors.toMap(Map.Entry::getKey, (entry) -> entry.getValue().getName());


Una forma es usar un colector toMap :

import static java.util.stream.Collectors.toMap; Map<String, String> byNameMap = people.entrySet().stream() .collect(toMap(Entry::getKey, e -> e.getValue().getName()));


Usando un poco de código genérico que lamentablemente no he encontrado en las bibliotecas que tenía a mano

public static <K, V1, V2> Map<K, V2> remap(Map<K, V1> map, Function<? super V1, ? extends V2> function) { return map.entrySet() .stream() // or parallel .collect(Collectors.toMap( Map.Entry::getKey, e -> function.apply(e.getValue()) )); }

Esto se vuelve esencialmente igual a Maps.transformValues menos las desventajas mencionadas por otros.

Map<String, Person> persons = ...; Map<String, String> byNameMap = remap(persons, Person::getName);

Y en caso de que necesite la clave así como el valor en su función de reasignación, esta segunda versión lo hace posible

public static <K, V1, V2> Map<K, V2> remap(Map<K, V1> map, BiFunction<? super K, ? super V1, ? extends V2> function) { return map.entrySet() .stream() // or parallel .collect(Collectors.toMap( Map.Entry::getKey, e -> function.apply(e.getKey(), e.getValue()) )); }

Se puede utilizar por ejemplo como

Map<String, String> byNameMap = remap(persons, (key, val) -> key + ":" + val.getName());