从地图中删除值为空的所有条目

时间:2017-10-31 22:53:47

标签: java collections java-stream optional

我想从地图中删除value为空的所有条目。看起来似乎并不复杂,但我试图找到一个更好的解决方案。

输入:

我有以下地图:

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

- 只是一个字符串和 - 对返回Optional&lt;的方法的引用字符串&gt;

输出:

结果,我想得到

Map<String, String> calculatedAttributes

(不包括值为空的条目可选)

这是我的解决方案

      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 部分,因为我必须在收集部分的可选项上调用 .get()

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

5 个答案:

答案 0 :(得分:12)

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

但是,我认为这段代码最好不使用流表达。

Optional

如果您不喜欢使用Map<String, String> result = new HashMap<>(); attributesToCalculate.forEach((k, v) -> v.apply(someString).ifPresent(str -> result.put(k, str)) ); 以这种方式填充地图,则可以使用简单的forEach循环。

答案 1 :(得分:4)

使用Guava,您可以这样做:

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

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

或者您可以考虑StreamEx&#39; EntryStream

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

答案 2 :(得分:2)

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

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

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

}, Map::putAll);

答案 3 :(得分:2)

您可以定义辅助方法来创建对:

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));

答案 4 :(得分:0)

使用普通的np.stack(np.meshgrid(x, y, z, indexing='ij'), axis=-1).reshape(-1, 3) 有什么问题?这看起来并不像其他一些流解决方案那么冗长。

Iterator

使用plain for循环甚至更短:

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());
    }
}