【问题标题】:Get map entries with matching keys using Stream API使用 Stream API 获取具有匹配键的地图条目
【发布时间】:2018-01-25 13:57:34
【问题描述】:

我有一个值数组

String [] str = { ONE, TWO, THREE };

以及一些存储在地图中的键值对

Map<String, String> map;

如何使用 Stream API 从映射中获取其键包含在数组中的所有条目?

【问题讨论】:

  • 请付出一些努力,到目前为止您尝试了什么?您自己解决这个问题到底有什么困难? (见help centerHow to Ask
  • 使用 Guava 你可以做到Map.filterKeys(map, Arrays.asList(str)::contains).
  • @shmosel 我刚刚查找了该方法并偶然发现:“返回的地图是unfiltered的实时视图”。您是否真的要使用一个映射,其中每个键查找都意味着通过数组进行线性搜索?
  • @Holger 取决于它的使用方式。如有必要,您可以轻松地将其复制到新地图。
  • @shmosel 当然,如果调用者意识到这个微妙之处。可能值得注意的是,还有标准的 API 可能性,例如result = new HashMap&lt;&gt;(map); result.keySet().retainAll(Arrays.asList( str));,或者甚至在原始地图上使用retainAll,如果它是可变的并且不再需要旧状态,因为JDK1.2......

标签: java hashmap java-stream


【解决方案1】:

我假设当你说你想要这张地图中的条目时,你的意思是值 所以这就是我的做法

    String[] str = {"ONE", "TWO", "THREE"};
    Map<String, String> map = <Your map's here>;

    List<String> values = Stream.of(str)
            .filter(map::containsKey)
            .map(map::get)
            .collect(Collectors.toList());

【讨论】:

  • 您可以使用.map(map::get).filter(Objects::nonNull)避免重复查找。
  • @shmosel 但在任何一种情况下,当您 filter 时,列表索引和源数组索引之间没有对应关系,这引发了一个问题,即是否真的打算跳过不在地图中的元素(与在列表中存储null
【解决方案2】:

如果地图和要删除的键集很小,请从地图的副本开始,然后对其进行修改。

Map<String, String> filtered = new HashMap<>(map);
filtered.keySet().retainAll(Arrays.asList(str));

如果映射比要删除的键集大得多以至于不希望复制,您可以构建一个仅包含正确条目的新映射:

Set<String> filter = new HashSet<>(Arrays.asList(str));
Map<String, String> filtered = map.entrySet().stream()
    .filter(e -> filter.contains(e.getKey))
    .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

【讨论】:

    【解决方案3】:

    您没有指定结果的形式。

    如果你想要相同的地图但只包含指定的键,你可以使用

    Map<String, String> map;
    Map<String, String> result = new HashMap<>(map);
    result.keySet().retainAll(Arrays.asList(str));
    

    如果不再需要旧状态并且映射是可变的,您可以将第二个语句应用于 map 而无需创建副本。

    总是创建一个新的Map 的解决方案是

    Map<String, String> result = Arrays.stream(str)
        .collect(HashMap::new, (m, k) -> m.computeIfAbsent(k, map::get), Map::putAll);
    

    如果您只想要一个包含与包含键的数组对应的值的数组,您可以使用

    String[] result = new String[str.length];
    Arrays.setAll(result, ix -> map.get(str[ix]));
    

    String[] result = Arrays.stream(str).map(map::get).toArray(String[]::new);
    

    【讨论】:

      【解决方案4】:

      一种方法是将数组流式传输并将元素收集到一个新地图中,其中键是元素,并且从地图中为每个键获取值:

      Map<String, String> result = Arrays.stream(str)
          .collect(Collectors.toMap(e -> e, map::get));
      

      这假定数组的所有元素都是映射中的键,并且数组上没有重复的元素。

      如果要过滤掉不是地图键的元素,请在流上使用filter

      Map<String, String> result = Arrays.stream(str)
          .filter(map::containsKey)
          .collect(Collectors.toMap(e -> e, map::get));
      

      如果数组中有重复的元素:

      Map<String, String> result = Arrays.stream(str)
          .filter(map::containsKey)
          .collect(Collectors.toMap(e -> e, map::get, (o, n) -> o));
      

      最后一个参数(o, n) -&gt; o 是一个合并函数,当地图上有重复键时,它会应用于值。在这种情况下,合并函数会保留旧值并丢弃新值。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-12-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-11
        • 2014-10-24
        • 1970-01-01
        相关资源
        最近更新 更多