Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

286
Views
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 answers
Answer question

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 Report

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 Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!