java - 如何从 Set/Map 中删除多个元素并知道哪些元素被删除了?

标签 java lambda java-stream

我有一个方法必须删除(小)Set<K> keysToRemove 中列出的任何元素来自一些(可能很大)Map<K,V> from .但是removeAll()不这样做,因为我需要返回所有实际删除的键,因为 map 可能包含也可能不包含需要删除的键。

老派代码直截了当:

public Set<K> removeEntries(Map<K, V> from) {
    Set<K> fromKeys = from.keySet();
    Set<K> removedKeys = new HashSet<>();
    for (K keyToRemove : keysToRemove) {
        if (fromKeys.contains(keyToRemove)) {
            fromKeys.remove(keyToRemove);
            removedKeys.add(keyToRemove);
        }
    }
    return removedKeys;
}

同样,使用流编写:

Set<K> fromKeys = from.keySet();
return keysToRemove.stream()
        .filter(fromKeys::contains)
        .map(k -> {
            fromKeys.remove(k);
            return k;
        })
        .collect(Collectors.toSet());

我觉得这更简洁一些,但我也觉得 lambda 太笨重了。

有什么建议可以以不那么笨拙的方式实现相同的结果吗?

最佳答案

“老派代码”应该是

public Set<K> removeEntries(Map<K, ?> from) {
    Set<K> fromKeys = from.keySet(), removedKeys = new HashSet<>(keysToRemove);
    removedKeys.retainAll(fromKeys);
    fromKeys.removeAll(removedKeys);
    return removedKeys;
}

既然你说 keysToRemove 相当小,复制开销可能并不重要。否则,使用循环,但不要进行两次哈希查找:

public Set<K> removeEntries(Map<K, ?> from) {
    Set<K> fromKeys = from.keySet();
    Set<K> removedKeys = new HashSet<>();
    for(K keyToRemove : keysToRemove)
        if(fromKeys.remove(keyToRemove)) removedKeys.add(keyToRemove);
    return removedKeys;
}

您可以将相同的逻辑表达为流

public Set<K> removeEntries(Map<K, ?> from) {
    return keysToRemove.stream()
        .filter(from.keySet()::remove)
        .collect(Collectors.toSet());
}

但由于这是一个有状态的过滤器,因此强烈建议不要这样做。一个更干净的变体是

public Set<K> removeEntries(Map<K, ?> from) {
    Set<K> result = keysToRemove.stream()
        .filter(from.keySet()::contains)
        .collect(Collectors.toSet());
    from.keySet().removeAll(result);
    return result;
}

如果你想最大化“流式”的使用,你可以将 from.keySet().removeAll(result); 替换为 from.keySet().removeIf(result: :contains),它非常昂贵,因为它正在迭代更大的 map ,或者使用 result.forEach(from.keySet()::remove),它没有但是,这个缺点并不比 removeAll 更具可读性。

总而言之,“老派代码”要好得多。

关于java - 如何从 Set/Map 中删除多个元素并知道哪些元素被删除了?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56582681/

相关文章:

java - 如何更改Spark SQL(在java中)DataFrame中的列类型?

python - Python 中没有多行 Lambda : Why not?

java - 具有返回类型的消费者接口(interface)的 lambda 表达式

java - 使用 Java 8 Streams 从另一个创建对象列表

java - 为什么 flatMap() 之后的 filter() 在 Java 流中是 "not completely"懒惰的?

java - 无法在 Weatherlib API android 上检索搜索到的城市

java - 对大矩阵(即 10,000 x 10,000)执行求逆

java - 服务器非托管线程中出现无法解释的 ClassNotFoundException

Java Stream优雅解决方案,避免多次循环

java - 收集到 treemap java 8