32

在 C# 中,我可以使用类似的东西:

List<string> myList = new List<string>();

if (myList.Count != myList.Distinct().Count())
{
    // there are duplicates
}

检查列表中的重复元素。但是,当列表中有null项目时,这会产生误报。我可以使用一些缓慢的代码来做到这一点,但是有没有办法检查列表中的重复项,同时以简洁的方式忽略空值?

4

5 回答 5

56

如果您担心性能问题,以下代码将在找到第一个重复项后立即停止 - 到目前为止,所有其他解决方案都要求整个输入至少迭代一次。

var hashset = new HashSet<string>();
if (myList.Where(s => s != null).Any(s => !hashset.Add(s)))
{
    // there are duplicates
}

hashset.Addfalse如果该项目已经存在于集合中,则返回,并在第一个值出现时立即Any返回,因此这只会搜索输入,直到第一个重复项。truetrue

于 2013-06-06T11:43:40.910 回答
32

我会这样做:

鉴于 Linq 语句将被延迟评估,因此.Any将短路 - 这意味着如果有重复项,您不必迭代和计算整个列表 - 因此,应该更有效。

var dupes = myList
    .Where(item => item != null)
    .GroupBy(item => item)
    .Any(g => g.Count() > 1);

if(dupes)
{
    //there are duplicates
}

编辑:http : //pastebin.com/b9reVaJu 一些似乎结束GroupBy的Linqpad 基准测试Count()更快

编辑 2: 下面罗林的回答似乎比这种方法至少快 5 倍!

于 2013-06-06T11:08:13.923 回答
11
var nonNulls = myList.Where(x => x != null)
if (nonNulls.Count() != nonNulls.Distinct().Count())
{
    // there are duplicates
}
于 2013-06-06T11:06:13.427 回答
4

好吧,两个空值是重复的,不是吗?

无论如何,比较没有空值的列表:

var denullified = myList.Where(l => l != null);
if(denullified.Count() != denullified.Distinct().Count()) ...
于 2013-06-06T11:06:41.003 回答
1

编辑我的第一次尝试很糟糕,因为它没有被推迟。

反而,

var duplicates = myList
    .Where(item => item != null)
    .GroupBy(item => item)
    .Any(g => g.Skip(1).Any());

删除了较差的实现。

于 2013-06-06T11:16:26.493 回答