Actualmente estoy trabajando con List<Map<String, Object>> donde intento agrupar varias claves dentro del mapa. Esto parece funcionar bien usando Java 8 Stream s:
Map<Object, Map<Object, List<Map<String, Object>>>> collect = list .stream() .collect(Collectors.groupingBy( item -> item.get("key1"), Collectors.groupingBy(item -> item.get("key2")) )); Como era de esperar, esto me da un Map<Object, Map<Object, List<Map<String, Object>>>> que funciona bien donde los posibles resultados agrupados son mayores que 1.
Tengo varios ejemplos en los que la agrupación que se realiza siempre dará como resultado un solo elemento en la lista de nivel más bajo, por ejemplo.
Lista de filas
{ [reference="PersonX", firstname="Person", dob="test", lastname="x"], [reference="JohnBartlett", firstname="John", dob="test", lastname="Bartlett"] }Agrupados por referencia
Actualmente - agrupados en una lista con 1 Map<String,Object>
[PersonX, { [reference="PersonX", firstname="Person", dob="test", lastname="x"]}], [JohnBartlett, { [reference="JohnBartlett", firstname="John", dob="test", lastname="Bartlett"]}] Preferencia - No lista solo un único Map<String,Object>
[PersonX, [reference="PersonX", firstname="Person", dob="test", lastname="x"]], [JohnBartlett, [reference="JohnBartlett", firstname="John", dob="test", lastname="Bartlett"]] ¿Hay alguna manera dentro de las secuencias para forzar que la salida de estas instancias sea Map<Object, Map<Object, Map<String, Object>>> , por lo que un solo Map<String,Object> en lugar de una List de ellos?
Cualquier ayuda sería muy apreciada.
Si entendí correctamente, entonces para los casos en los que está seguro de que hay un solo elemento, simplemente debe reemplazar:
.collect(Collectors.groupingBy( item -> item.get("key1"), Collectors.toMap(item -> item.get("key2"), Function.identity()) )); Incluso puede proporcionar un tercer argumento como BinaryOperator para fusionar sus mismas entradas (en caso de que lo necesite)
Collectors.toMap() hace exactamente lo que está buscando hacer.
Map<Object, Map<String, Object>> collect = maps.stream() .collect(Collectors.toMap(p -> p.get("reference"), Function.identity())); { PersonX={firstname=Person, reference=PersonX, lastname=x, dob=test}, JohnBartlett={firstname=John, reference=JohnBartlett, lastname=Bartlett, dob=test} } Esto arrojará una IllegalStateException si tiene una clave duplicada, que probablemente sea exactamente lo que desea cuando nunca espera que haya un registro duplicado en sus datos:
Exception in thread "main" java.lang.IllegalStateException: Duplicate key JohnBartlett (attempted merging values {dob=test, lastname=Bartlett, reference=JohnBartlett, firstname=John} and {dob=test 2, lastname=Bartlett, reference=JohnBartlett, firstname=John}) at java.base/java.util.stream.Collectors.duplicateKeyException(Collectors.java:133) at java.base/java.util.stream.Collectors.lambda$uniqKeysMapAccumulator$1(Collectors.java:180) at java.base/java.util.stream.ReduceOps$3ReducingSink.accept(ReduceOps.java:169) at java.base/java.util.AbstractList$RandomAccessSpliterator.forEachRemaining(AbstractList.java:720) at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484) at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474) at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:913) at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:578) at so.UniqueKeyStreamExample.main(UniqueKeyStreamExample.java:22)