使用Guava从列表中删除重复项

34

如何使用 Guava API 从列表中删除重复项?

目前我正在遵循以下方法:

private List<T> removeDuplicate(List<T> list){
return new ArrayList<T>(new LinkedHashSet<T>(list));
}

5
为什么你喜欢吃番石榴,如果基础套餐已经包含了它呢? - jmj
而且如此简洁明了。 - Thilo
@PriyankDoshi 为什么不使用 HashSet - obataku
3
好的,我会尽力进行翻译:@veer : 我需要保持顺序。所以使用了 LinkedHashSet - Priyank Doshi
6
@MohammodHossain 不,LinkedHashSet 是正确的选择,因为它会保留元素的顺序。 - Bohemian
显示剩余3条评论
6个回答

70

最有效的方法可能是使用 ImmutableSet.copyOf(list).asList(), 它可以消除重复项并保留迭代顺序。

(但是如果您实际上需要在集合中包含 null 值,在使用 LinkedHashSet 实现时也是几乎同样高效并且不会出错。)


3
如果你没有空元素 ;) - Grzegorz Rożniecki
2
真的,但是95%的集合并不这样。 - Louis Wasserman

12

我喜欢Louis的答案,因为它很简单易懂(而且是唯一一个不需要完全遍历两次的答案),但可惜在现实世界中,你经常会遇到null出现的情况。这里是一个稍微长一点的null安全版本:

ImmutableSet.copyOf(
    Iterables.filter(
        list, Predicates.not(Predicates.isNull()))).asList();

或者,使用静态导入:

copyOf(filter(list, not(isNull()))).asList();

当然,您需要意识到所有null值将从列表中丢失。


3
已经有一个 Predicates.notNull() 谓词可用。因此最终结果将是 copyOf(filter(list, notNull())).asList(); - Jonas
@Jonas 是的,但是在我写这篇文章的时候,这个方法还不存在。 - Sean Patrick Floyd

7

使用泛型谓词

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

}

2
请注意,set.add仅在实际添加元素时返回true,因此调用set.contains是不必要的。 - Hakanai

1

我真的不建议使用(Linked)HashMultiSet来完成通常使用ArrayList(Linked)HashSet来完成的任务,就像OP上面提到的那样-对于普通的Java程序员来说可读性较差,而且(可能)效率也较低。

相反,至少要使用静态工厂构造函数,如newArrayListnewLinkedHashSet,以避免所有这些<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()返回一个视图。


1

如果你想不惜一切使用Guava,那么你可以这样做。

return new ArrayList<T>(HashMultiSet<T>.create(list).elementSet())

0
你可以尝试使用Guava的MultiSet API来去除重复项。只需将列表添加到集合中并使用count方法即可。

MultiSet


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接