如何在Java 8中按其值过滤地图?

Naz*_*ila 21 java java-8

我有一个地图,其中值是字符串,键是列表:Map<String, List<BoMLine>> materials.我想用它的值过滤这个地图; 这样的事情:

materials.entrySet().stream()
       .filter(a->a.getValue().stream()
           .filter(l->MaterialDao.findMaterialByName(l.getMaterial()).ispresent)
Run Code Online (Sandbox Code Playgroud)

但这对我不起作用.有人有想法吗?

谢谢.

Era*_*ran 29

如果我正确理解了您的过滤条件,您需要检查Stream从该值生成的过滤是否List包含任何元素,如果是,则将相应的Map条目传递给输出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()));
Run Code Online (Sandbox Code Playgroud)

假设MaterialDao.findMaterialByName(l.getMaterial())返回a boolean.

  • 你不需要使用`filter()`,只需将谓词作为参数传递给`anyMatch()`. (3认同)
  • @FedericoPeraltaSchaffner谢谢.我在没有检查API的情况下从内存中回答.我会解决它. (2认同)

Mat*_*aun 18

通常,您可以按照其值过滤地图:

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));
}
Run Code Online (Sandbox Code Playgroud)

像这样称呼它:

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);
Run Code Online (Sandbox Code Playgroud)

  • 如果有人想知道,上面代码片段中的 `Entry::getKey` 和 `Entry::getValue` 实际上指的是 `java.util.Map.Entry::getKey` (需要 `import java.util.Map` 或 ` java.util.Map.Entry`) (2认同)

rus*_*tyx 5

以前的所有答案都提供了一个解决方案,可以创建一个新的Map. 如果您只想删除几个条目,这可能效率低下。

以下内容从现有 中 删除元素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);
Run Code Online (Sandbox Code Playgroud)

印刷:

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);
Run Code Online (Sandbox Code Playgroud)

它是如何工作的?它将所有需要删除的密钥收集到一个临时 中List,然后Map一次性将它们从原始密钥中删除。临时List是必需的,因为修改 aMap会使流和迭代器无效。但是,Map与构建List.

如果您想删除大量条目(50% 或更多),那么最好Map确实构建一个新条目。