Nazila
Tengo un mapa donde los valores son cadenas y las claves son listas:
Map<String, List<BoMLine>> materials
Me gustaría filtrar este mapa por sus valores; algo como esto:
materials.entrySet().stream()
.filter(a -> a.getValue().stream()
.filter(l -> MaterialDao.findMaterialByName(l.getMaterial()).ispresent)
Pero no está funcionando para mí. Alguien tiene una idea?
Eran
Si entiendo correctamente sus criterios de filtrado, desea verificar si el filtrado Stream
usted produjo a partir del valor List
tiene algún elemento, y en caso afirmativo pasar el correspondiente Map
entrada a la salida Map
.
Map<String, List<BoMLine>>
filtered = materials.entrySet()
.stream()
.filter(a->a.getValue()
.stream()
.anyMatch(l->MaterialDao.findMaterialByName(l.getMaterial())))
.collect(Collectors.toMap(e->e.getKey(),e->e.getValue()));
esto es asumiendo MaterialDao.findMaterialByName(l.getMaterial())
devuelve un boolean
.
-
No estoy seguro de mi solución y no funciona cuando quiero recopilarla en el mapa “e” no es un mapa, es solo un objeto
– Nazila
1 de noviembre de 2015 a las 7:25
-
@nazila
e
es unMap.Entry<String,List<BoMLine>>
. Cometí algunos errores de sintaxis tontos en la llamada acollect
. Ver respuesta editada.– Eran
1 de noviembre de 2015 a las 7:33
-
No necesitas usar
filter()
simplemente pase el predicado como argumento aanyMatch()
.– fps
1 de noviembre de 2015 a las 12:59
-
@FedericoPeraltaSchaffner Gracias. Respondí de memoria sin consultar la API. Lo arreglaré.
– Eran
1 de noviembre de 2015 a las 13:03
-
@Eran Intenté filtrar usando lo mismo, pero cuando tengo un valor nulo en uno de los objetos, arroja una excepción de puntero nulo. ¿Cómo puedo evitar eso?
– Bravo
13 de diciembre de 2021 a las 18:22
Generalmente, así es como puede filtrar un mapa por sus valores:
static <K, V> Map<K, V> filterByValue(Map<K, V> map, Predicate<V> predicate) {
return map.entrySet()
.stream()
.filter(entry -> predicate.test(entry.getValue()))
.collect(Collectors.toMap(Entry::getKey, Entry::getValue));
}
Llámalo así:
Map<String, Integer> originalMap = new HashMap<>();
originalMap.put("One", 1);
originalMap.put("Two", 2);
originalMap.put("Three", 3);
Map<String, Integer> filteredMap = filterByValue(originalMap, value -> value == 2);
Map<String, Integer> expectedMap = new HashMap<>();
expectedMap.put("Two", 2);
assertEquals(expectedMap, filteredMap);
-
En caso de que alguien se lo pregunte,
Entry::getKey
&Entry::getValue
en el fragmento anterior en realidad se refiere ajava.util.Map.Entry::getKey
(Necesitarimport java.util.Map
ojava.util.Map.Entry
para ello)– y2k-shubham
8 de agosto de 2022 a las 10:05
Todas las respuestas anteriores proporcionan una solución que crea una nueva Map
. Esto puede ser ineficaz si desea eliminar solo unas pocas entradas.
Lo siguiente elimina los elementos de la existente Map
:
Map<String, Integer> myMap = new HashMap<>();
myMap.put("One", 1);
myMap.put("Two", 2);
myMap.put("Three", 3);
myMap.keySet().removeAll(
myMap.entrySet().stream()
.filter(a->a.getValue().equals(2))
.map(e -> e.getKey()).collect(Collectors.toList()));
System.out.println(myMap);
Huellas dactilares:
{One=1, Three=3}
¿Como funciona? Recoge todo llaves que necesitan ser removidos en un temporal List
luego los elimina del original Map
en una ida. Un temporal List
es necesario porque la modificación de un Map
invalida flujos e iteradores. Sin embargo, la construcción de un nuevo Map
es potencialmente una operación mucho más costosa que construir un List
.
Si desea eliminar muchas entradas (50% o más), entonces es mejor crear una nueva Map
en efecto.
Nazila
Finalmente lo hice funcionar. Mi segundo filtro fue completamente inútil. La respuesta es así:
Map<String, List<BoMLine>>
filtered = materials.entrySet()
.stream()
.filter(a -> a
.getValue()
.stream()
.allMatch(
b -> MaterialDao.findMaterialByName(
b.getMaterial()).isPresent()))
.collect(Collectors.toMap(p -> p.getKey(), p -> p.getValue()))
En mi humilde opinión, uno de los códigos Java 8 más concisos puede verse así:
public Map<String, ReportPlaceholderValue> getAllPlaceholders() {
Map<String, ReportPlaceholderValue> result = chamberDetailsPlaceHolders;
result.entrySet().stream().filter( e -> !(e.getValue() instanceof StringReportPlaceholderValue) )
.map( Map.Entry::getKey )
.collect( Collectors.toList() ).forEach( result.keySet()::remove );
return result;
}