如何使用 Java 流 api 过滤地图?

How to filter a map with Java stream api?

Map<Integer, String> map = new HashMap<>();
  map.put(1, "f");
  map.put(2, "I");
  map.put(3, "a");
  map.put(4, "c");....etc

现在我有一个列表:

List<Integer> picks = {1,3}

我想取回一个字符串列表,即映射中与键值匹配的值,在 'pick' list.So 中找到,我期待返回 {"f", "a"} 作为结果。有没有办法使用 java 流 api 以优雅的方式做到这一点?

当有一个值时,我是这样做的:

map.entrySet().stream()
   .filter(entry -> "a".equals(entry.getValue()))
   .map(entry -> entry.getValue())
   .collect(Collectors.toList())

但是当有 keys/picks 的列表可供过滤时,会遇到困难。

您可以使用类似这样的方法实现此目的:

List<String> values = map.entrySet()
                .stream()
                .filter(entry -> picks.contains(entry.getKey()))
                .map(Map.Entry::getValue)
                .collect(Collectors.toList());

values.forEach(System.out::println);

输出:

f
a

但是它可能效率不高,因为 List::contains 是 O(N)。考虑对 picks 使用 Set (for example HashSet) 而不是 List 因为 HashSet::contains 是 O(1).

您可以在 Stream#filter 中使用 List.contains() 以仅接受列表中存在的那些值:

List<String> result = map.entrySet()
   .stream()
   .filter(ent -> picks.contains(ent.getKey()))
   .map(Map.Entry::getValue)     
   .collect(Collectors.toList());

您不需要遍历整个地图来收集选取的值。而是遍历所需的键并从地图中获取相关值。如果地图与您需要选择的值相比要大得多(通常是这种情况),那么这种方法应该优于另一种方法。此外,这个解决方案更加紧凑,对我来说视觉混乱更少。这是它的样子。

List<String> pickedValues = picks.stream().map(map::get)
    .filter(Objects::nonNull)
    .collect(Collectors.toList());