如何从“设置/地图"中删除多个元素并知道删除了哪些元素? [英] How to remove multiple elements from Set/Map AND knowing which ones were removed?
问题描述
我有一种方法必须从某些(可能很大)Map<K,V> from
中删除(小)Set<K> keysToRemove
中列出的任何元素.但是removeAll()
不会,因为我需要返回实际上已删除的所有键,因为映射可能包含或可能不包含需要删除的键.
I have a method that has to remove any element listed in a (small) Set<K> keysToRemove
from some (potentially large) Map<K,V> from
. But removeAll()
doesn't do, as I need to return all keys that were actually removed, since the map might or might not contain keys that require removal.
老式代码很简单:
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太笨拙了.
I find that a bit more concise, but I also find that lambda too clunky.
有人建议如何以较少笨拙的方式获得相同的结果吗?
Any suggestions how to achieve the same result in less clumsy ways?
推荐答案
老式代码"应该是
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
很小,因此复制开销可能无关紧要.否则,请使用循环,但不要进行两次哈希查找:
Since you said that keysToRemove
is rather small, the copying overhead likely doesn’t matter. Otherwise, use the loop, but don’t do the hash lookup twice:
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;
}
您可以表达与流相同的逻辑
You can express the same logic as a stream as
public Set<K> removeEntries(Map<K, ?> from) {
return keysToRemove.stream()
.filter(from.keySet()::remove)
.collect(Collectors.toSet());
}
但是由于这是一个有状态的过滤器,因此不建议使用.更干净的变体是
but since this is a stateful filter, it is highly discouraged. A cleaner variant would be
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)
,这很便宜,因为它在较大的地图上进行迭代,或者替换为result.forEach(from.keySet()::remove)
,而不会有这个缺点,但仍然比removeAll
更具可读性.
and if you want to maximize the "streamy" usage, you can replace from.keySet().removeAll(result);
with from.keySet().removeIf(result::contains)
, which is quiet expensive, as it is iterating over the larger map, or with result.forEach(from.keySet()::remove)
, which doesn’t have that disadvantage, but still, isn’t more readable than removeAll
.
总而言之,老式代码"比这要好得多.
All in all, the "old-school code" is much better than that.
这篇关于如何从“设置/地图"中删除多个元素并知道删除了哪些元素?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!