如何从“设置/地图"中删除多个元素并知道删除了哪些元素? [英] How to remove multiple elements from Set/Map AND knowing which ones were removed?

查看:54
本文介绍了如何从“设置/地图"中删除多个元素并知道删除了哪些元素?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一种方法必须从某些(可能很大)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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆