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

287
Vistas
Cómo combinar los valores del mapa del mapa principal con el flujo de Java 8

Tengo un mapa dentro de un mapa que se ve así:

 Map<String, Map<Integer, BigDecimal>> mapInMap; //--> with values like: /* "a": (1: BigDecimal.ONE), "b": (2: BigDecimal.TEN), "c": (1: BigDecimal.ZERO) */

Y me gustaría combinar los mapas internos esperando el siguiente resultado:

 Map<Integer, BigDecimal> innerMapCombined; //--> with values: /* 1: BigDecimal.ZERO, 2: BigDecimal.TEN */

Esta es mi solución predefiniendo el mapa combinado y usando forEach:

 Map<Integer, BigDecimal> combined = new HashMap<>(); mapInMap.forEach((str, innerMap) -> { innerMap.forEach(combined::putIfAbsent); });

Pero esto ignorará (1: BigDecimal.ZERO) .

¿Podría proporcionar una solución de 1 línea con java 8 stream?

over 4 years ago · Santiago Trujillo
2 Respuestas
Responde la pregunta

0

El problema con su problema es que tan pronto como inicialice sus mapas y agregue las claves duplicadas en los mapas internos, volverá a escribir esas claves, ya que esos mapas no aceptan claves duplicadas. Por lo tanto, primero debe cambiar esto:

 Map<String, Map<Integer, BigDecimal>> mapInMap;

a un Map que permite claves duplicadas , por ejemplo Multimap de Google Guava:

 Map<String, Multimap<Integer, BigDecimal>> mapInMap = new HashMap<>();

donde los mapas internos se crean así:

 Multimap<Integer, BigDecimal> x1 = ArrayListMultimap.create(); x1.put(1, BigDecimal.ONE); mapInMap.put("a", x1);

Solo ahora puede intentar resolver su problema utilizando Java 8 Streams API. Por ejemplo:

 Map<Integer, BigDecimal> map = multiMap.values() .stream() .flatMap(map -> map.entries().stream()) .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (v1, v2) -> v2));

Los conflictos de claves duplicadas se resuelven utilizando el parámetro mergeFunction del método toMap . Expresamos explícitamente tomar el segundo valor (v1, v2) -> v2 en caso de duplicados.

over 4 years ago · Santiago Trujillo Denunciar

0

Problema:

Para abordar por qué su solución actual no funciona es porque el método Map#putIfAbsent solo agrega y no reemplaza un valor en un mapa si ya está presente.


Solución usando for-each:

Map#put es un camino a seguir, sin embargo, su limitación es que no puede decidir si desea mantener siempre el primer valor para dicha clave, calcular uno nuevo o usar siempre el último valor. Por tal razón, recomiendo usar una combinación de Map#computeIfPresent y Map#putIfAbsent o, mejor, un método que haga todo eso a la vez, que es Map#merge(K, V, BiFunction) con una función de reasignación de BiFunction remappingFunction :

remappingFunction - la función para volver a calcular un valor si está presente

 Map<Integer, BigDecimal> resultMap = new HashMap<>(); for (Map<Integer, BigDecimal> map: mapInMap.values()) { for (Map.Entry<Integer, BigDecimal> entry: map.entrySet()) { resultMap.merge(entry.getKey(), entry.getValue(), (l, r) -> r); } }

Solución usando Stream API:

Para reescribirlo en la solución Stream-alike, el enfoque sería idéntico. La única diferencia es la sintaxis declarativa de Stream API, sin embargo, la idea es la misma.

Simplemente haga un mapeo plano de la estructura y recopile en un mapa con un Collector.toMap(Function, Function, BinaryOperator usando BinaryOperator mergeFunction para fusionar claves duplicadas.

mergeFunction: una función de combinación, utilizada para resolver colisiones entre valores asociados con la misma clave, como se proporciona a Map.merge(Object, Object, BiFunction)

 Map<Integer, BigDecimal> resultMap = mapInMap.values().stream() .flatMap(entries -> entries.entrySet().stream()) .collect(Collectors.toMap( Map.Entry::getKey, Map.Entry::getValue, (l, r) -> r));

Nota: @dreamcrash también merece crédito por su buena respuesta de Stream API en términos de velocidad.


Resultado:

{1=1, 2=10} es el resultado cuando extrae dicho mapa (tenga en cuenta que BigDecimal se imprime como un número). Esta salida coincide con su salida esperada.

 1=BigDecimal.ZERO 2=BigDecimal.TEN

Observe las similitudes entre Map#merge(K, V, BiFunction) y Collector.toMap(Function, Function, BinaryOperator que usan un enfoque muy similar para el mismo resultado.

over 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