【问题标题】:Remove all entries where value is an empty Optional from map从 map 中删除 value 为空 Optional 的所有条目
【发布时间】:2017-10-31 22:53:46
【问题描述】:

我想从地图中删除 value 为空 Optional 的所有条目。看起来没什么复杂的,但我正在尝试找到一个更好的解决方案。


输入:

我有以下地图:

Map<String, Function<String, Optional<String>>> attributesToCalculate = new HashMap<>();

其中 key - 只是一个字符串和 value - 对返回 Optional

的方法的引用

输出:

结果,我想得到

Map<String, String> calculatedAttributes

(不包括 value 为空 Optional 的条目)


这是我的解决方案

      return attributesToCalculate.entrySet()
        .stream()
        .map(entry -> Pair.of(entry.getKey(), entry.getValue().apply(someString)))
        .filter(entry -> entry.getValue().isPresent())
        .collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().get()));

但我不喜欢 .filter 部分,因为我必须在 collect 部分中的 Optional 上调用 .get()

有没有更好的方法(可能没有 .get 调用)来解决这个问题?谢谢。

【问题讨论】:

  • 如果你之前检查过有值,调用get()没有错。
  • 好问题,伙计 :) 如果您在类路径中有 StreamEx,您可以通过 EntryStream#mapValues/filterValues 将值与键分开处理。但我会继续 @Paul Boddington 的回答,因为它不会滋生不需要的 Pairs。
  • @AndrewTobilko,嗨 :) 我也这么认为。保罗的回答完全适合我的情况。至于 StreamEx,不幸的是,我们不使用它 =/

标签: java collections java-stream optional


【解决方案1】:

不是很漂亮,类似于for循环:

 return attributesToCalculate.entrySet().stream().collect(HashMap::new, (sink, entry) -> {

    entry.getValue().apply(someString).ifPresent(v -> sink.put(entry.getKey(), v));

}, Map::putAll);

【讨论】:

  • 这里不需要语句语法,你可以简单地使用(map,entry) -&gt; entry.getValue().apply(someString).ifPresent(v -&gt; map.put(entry.getKey(),v))作为累加器函数。并且没有理由提供像空块这样的无效合并功能,因为简单的(m1, m2) -&gt; m1.putAll(m2) 或更简单的Map::putAll 就可以完成这项工作。
  • @Holger 谢谢。修复了combiner 部分。 (虽然我将保留语句语法,但我什至会将累加器提取到一个单独的变量中,因为它太长了恕我直言,但我相信 OP 需要一个单行)
【解决方案2】:

如上所述,如果您已经检查过Optional 不为空,则使用get 没有任何问题。

不过,我认为这段代码最好不用流来表达。

Map<String, String> result = new HashMap<>();
attributesToCalculate.forEach((k, v) ->
    v.apply(someString).ifPresent(str -> result.put(k, str))
);

如果您不喜欢使用forEach 以这种方式填充地图,则可以改用简单的for 循环。

【讨论】:

    【解决方案3】:

    使用 Guava,您可以这样做:

    Maps.filterValues(
            Maps.transformValues(
                    attributesToCalculate,
                    f -> f.apply("someString").orElse(null)),
            Predicates.notNull())
    

    请注意,这会返回底层地图的视图,这意味着任何查找或迭代都将委托给该函数。如果这是个问题,只需将结果复制到新地图即可。

    或者你可以考虑StreamExEntryStream

    EntryStream.of(attributesToCalculate)
            .mapValues(f -> f.apply("someString"))
            .flatMapValues(StreamEx::of)
            .toMap();
    

    【讨论】:

      【解决方案4】:

      您可以定义一个辅助方法来创建您的 Pair:

      public static <L, R> Optional<Pair<L, R>> of2(L left, Optional<R> right) {
          return right.map(r -> Pair.of(left, r));
      }
      

      虽然这意味着使用 Optional 作为参数,但在这种情况下,imo 并没有那么糟糕(如果您内联该方法,您就不会将它作为参数...)。

      那么你可以这样做:

      attributesToCalculate.entrySet()
           .stream()
           .map(entry -> of2(entry.getKey(), entry.getValue().apply(someString)))
           .flatMap(Optional::stream) // Java 9
           .collect(Collectors.toMap(Map.Entry::getKey, Pair::getValue));
      

      【讨论】:

      • 您可以简单地将mapflatMap 步骤组合成一个.flatMap(entry -&gt; entry.getValue() .apply(someString).map(s -&gt; Pair.of(entry.getKey(), s)).stream())
      【解决方案5】:

      使用普通的旧 Iterator 有什么问题?这看起来并不比其他一些流解决方案更冗长。

      final Map<String, Optional<Object>> attributesToCalculate = new HashMap<>();
      final Map<String, Object> calculatedAttributes = new HashMap<>();
      
      final Iterator<Entry<String, Optional<Object>>> iter = attributesToCalculate.entrySet().iterator();
      while (iter.hasNext()) {
          final Entry<String, Optional<Object>> current = iter.next();
          if (current.getValue().isPresent()) {
              calculatedAttributes.put(current.getKey(), current.getValue().get());
          }
      }
      

      使用普通的 for 循环甚至更短:

      for(Entry<String, Optional<Object>> current : attributesToCalculate.entrySet()) {
          if (current.getValue().isPresent()) {
              calculatedAttributes.put(current.getKey(), current.getValue().get());
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2023-03-28
        • 2013-04-24
        • 1970-01-01
        • 1970-01-01
        • 2019-05-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-07-20
        相关资源
        最近更新 更多