Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

253
Vistas
Java 8 stream.collect (... groupingBy (... mapeo (... reduce))) reduce el uso de BinaryOperator

Jugué con una solución usando groupingBy , mapping y reducing a la siguiente pregunta: Cree elegantemente un mapa con campos de objetos como clave/valor de flujo de objetos en Java 8 . Resumiendo, el objetivo era conseguir un mapa con la edad como clave y las aficiones de una persona como Set .

Una de las soluciones que se me ocurrió (no es agradable, pero ese no es el punto) tenía un comportamiento extraño.

Con la siguiente lista como entrada:

 List<Person> personList = Arrays.asList( new Person(/* name */ "A", /* age */ 23, /* hobbies */ asList("a")), new Person("BC", 24, asList("b", "c")), new Person("D", 23, asList("d")), new Person("E", 23, asList("e")) );

y la siguiente solución:

 Collector<List<String>, ?, Set<String>> listToSetReducer = Collectors.reducing(new HashSet<>(), HashSet::new, (strings, strings2) -> { strings.addAll(strings2); return strings; }); Map<Integer, Set<String>> map = personList.stream() .collect(Collectors.groupingBy(o -> o.age, Collectors.mapping(o -> o.hobbies, listToSetReducer))); System.out.println("map = " + map);

Obtuve:

 map = {23=[a, b, c, d, e], 24=[a, b, c, d, e]}

claramente no es lo que esperaba. Más bien esperaba esto:

 map = {23=[a, d, e], 24=[b, c]}

Ahora, si solo reemplazo el orden de (strings, strings2) del operador binario (del colector reductor) a (strings2, strings) obtengo el resultado esperado. Entonces, ¿qué me perdí aquí? ¿Interpreté mal el colector reducing ? ¿O qué parte de la documentación me perdí que hace evidente que mi uso no estaba funcionando como se esperaba?

La versión de Java es 1.8.0_121 si eso importa.

about 4 years ago · Santiago Trujillo
1 Respuestas
Responde la pregunta

0

La reducción nunca debe modificar los objetos entrantes. En su caso, está modificando el HashSet entrante que se supone que es el valor de identidad y lo devuelve, por lo que todos los grupos tendrán como resultado la misma instancia de HashSet , que contiene todos los valores.

Lo que necesita es una Reducción mutable , que se puede implementar a través de Collector.of(…) como si ya se hubiera implementado con los recopiladores prediseñados Collectors.toList() , Collectors.toSet() , etc.

 Map<Integer, Set<String>> map = personList.stream() .collect(Collectors.groupingBy(o -> o.age, Collector.of(HashSet::new, (s,p) -> s.addAll(p.hobbies), (s1,s2) -> { s1.addAll(s2); return s1; })));

La razón por la que necesitamos un recopilador personalizado es que Java 8 no tiene el recopilador flatMapping , que Java 9 va a presentar. Con eso, la solución se verá así:

 Map<Integer, Set<String>> map = personList.stream() .collect(Collectors.groupingBy(o -> o.age, Collectors.flatMapping(p -> p.hobbies.stream(), Collectors.toSet())));
about 4 years ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda