如何使用 Guava API 从列表中删除重复项?
目前我正在遵循以下方法:
private List<T> removeDuplicate(List<T> list){
return new ArrayList<T>(new LinkedHashSet<T>(list));
}
最有效的方法可能是使用 ImmutableSet.copyOf(list).asList()
, 它可以消除重复项并保留迭代顺序。
(但是如果您实际上需要在集合中包含 null 值,在使用 LinkedHashSet
实现时也是几乎同样高效并且不会出错。)
我喜欢Louis的答案,因为它很简单易懂(而且是唯一一个不需要完全遍历两次的答案),但可惜在现实世界中,你经常会遇到null
出现的情况。这里是一个稍微长一点的null安全版本:
ImmutableSet.copyOf(
Iterables.filter(
list, Predicates.not(Predicates.isNull()))).asList();
或者,使用静态导入:
copyOf(filter(list, not(isNull()))).asList();
当然,您需要意识到所有null
值将从列表中丢失。
Predicates.notNull()
谓词可用。因此最终结果将是 copyOf(filter(list, notNull())).asList();
。 - Jonas使用泛型谓词
class DuplicateRemover<T> implements Predicate<T> {
private final Set<T> set = new HashSet<>();
@Override
public boolean apply(T input) {
boolean flag = set.contains(input);
if (!flag) {
set.add(input);
}
return !flag;
}
}
我真的不建议使用(Linked)HashMultiSet
来完成通常使用ArrayList
和(Linked)HashSet
来完成的任务,就像OP上面提到的那样-对于普通的Java程序员来说可读性较差,而且(可能)效率也较低。
相反,至少要使用静态工厂构造函数,如newArrayList
和newLinkedHashSet
,以避免所有这些<T>
:
private static <T> List<T> removeDuplicate(final List<T> list) {
return Lists.newArrayList(Sets.newLinkedHashSet(list));
}
然而,您可以以更“Guava方式”完成它 - 通过避免null值并使用不可变集合。
因此,如果您的集合不能具有null元素,则建议使用不可变集合而不是可变且效率较低的集合:
private static <T> List<T> removeDuplicate(final List<T> list) {
return Lists.newArrayList(ImmutableSet.copyOf(list));
}
它仍然会复制对象两次,因此请考虑完全不可变并更改方法签名以返回ImmutableList
:
private static <T> ImmutableList<T> removeDuplicate(final List<T> list) {
return ImmutableSet.copyOf(list).asList();
}
这样只涉及到一次复制,因为ImmutableCollection.asList()
返回一个视图。
如果你想不惜一切使用Guava,那么你可以这样做。
return new ArrayList<T>(HashMultiSet<T>.create(list).elementSet())
HashSet
? - obatakuLinkedHashSet
是正确的选择,因为它会保留元素的顺序。 - Bohemian