如何在 List<string> 中查找具有重复值的列表

74
如何查找 List<string> 是否有重复值?我尝试了下面的代码。有更好的方法吗?
var lstNames = new List<string> { "A", "B", "A" };

if (lstNames.Distinct().Count() != lstNames.Count())
{
    Console.WriteLine("List contains duplicate values.");
}

1
抱歉,大家……我错过了简单的逻辑。 - Prasad Kanaparthi
23
请不要说抱歉。我们都在这里学习。 - Soner Gönül
5个回答

126

尝试使用 GroupByAny,如下所示:

lstNames.GroupBy(n => n).Any(c => c.Count() > 1);

GroupBy方法;

根据指定的键选择器函数对序列的元素进行分组,并使用指定的函数为每个组投影元素。

Any方法,它返回boolean

确定序列中是否存在任何元素或是否满足条件。


5
这种方式与原始代码相比有什么优点?你仍然需要将所有项分组,因此在这里并没有任何短路。 - Servy
6
这不仅需要遍历所有元素来构建分组,还可能需要遍历所有分组。你最初的咖啡会更快。 - Rawling
22
该死的自动校正。 - Rawling
1
根据我的测试,原始代码至少比这个代码快1.5倍(取决于输入)。 - GorkemHalulu
3
c.Count() > 1 替换为 c.Skip(1).Any() 如何? - Oliver
显示剩余2条评论

50

如果你正在寻找最高效的方法,

var lstNames = new List<string> { "A", "B", "A" };
var hashset = new HashSet<string>();
foreach(var name in lstNames)
{
    if (!hashset.Add(name))
    {
        Console.WriteLine("List contains duplicate values.");
        break;
    }
}

一旦找到第一个重复项,程序就会停止。如果你需要在多个位置使用它,可以将其封装在一个方法(或扩展方法)中。


2
在最坏的情况下,与“GroupBy”相比,性能提高了10倍。 - Ilya Ivanov
2
实际上,在最坏的情况下(没有重复项),它大约相同,可能只会快一点。在最好的情况下(前两个项目是重复的),它会快100%,因为它将是O(1),而不是O(n)。在一般情况下,它将取决于底层数据中实际重复项的比率,而“GroupBy”和“Distinct”则无论底层数据如何都需要相同的时间。 - Servy
1
“O”在这里表示“最坏情况”。没有“在最好的情况下它将是O(x)”。 - John Shedletsky
3
@JohnShedletsky 提到的'O(f)'表示一组函数,它们的增长速度不比f(x)快,也就是说,对于所有属于O(f)的函数g(x),存在一个常数C,使得当x足够大时,g(x) <= f(x) * C。这并不涉及最好或最坏情况。 - Flonk

29

基于哈希技术的通用且简洁的扩展版本答案:

public static bool AreAnyDuplicates<T>(this IEnumerable<T> list)
{
    var hashset = new HashSet<T>();
    return list.Any(e => !hashset.Add(e));
}

1
很酷,我已经将它添加到我的Linq扩展中了。不过,我添加了一个重载来提供比较器。 - Eluvatar
我知道这个方法很老了,虽然创建扩展方法很酷,但从性能的角度来看,这真的很糟糕。它应该使用group by而不是尝试将每个列表对象插入到hashset中。 - curiousBoy
@curiousBoy 我非常确定GroupBy是使用某种哈希结构在内部实现的,因此基本上它应该具有相同的性能。据我所知,向HashSet添加元素在计算方面是“便宜”的,并且最多使用与原始列表相同的内存量。此外,我不确定在彼此之后拥有GroupByAny可能不是非常懒惰,而显然这个解决方案将停止在第一个重复项上。您能否请澄清一下为什么您认为它的性能很差? - Zoltán Tamási
@Eluvatar,我知道你很久以前已经回答过这个问题了,但是如果你愿意分享你的代码,我会很高兴的。谢谢! - Erick Brown
2
@ErickBrown HashSet<T>的构造函数确实接受自定义比较器,我认为@Eluvatar的意思是将其作为此扩展的参数公开。 - Zoltán Tamási

12
var duplicateExists = lstNames.GroupBy(n => n).Any(g => g.Count() > 1);

1
哦,我错过了简单的逻辑。 - Prasad Kanaparthi
我认为使用Any()比Count()更好,但我不知道Distinct()和GroupBy()之间的性能差异。 - Nasmi Sabeer
我认为在List<someClass>的情况下,您需要按所有项目进行分组,然后再对所有项目应用Any()。我不确定如何在我的示例中仅使用Count()进行比较。 - Prasad Kanaparthi

0
 class Program
{
    static void Main(string[] args)
    {
        var listFruits = new List<string> { "Apple", "Banana", "Apple", "Mango" };
        if (FindDuplicates(listFruits)) { WriteLine($"Yes we find duplicate"); };
        ReadLine();
    }
    public static bool FindDuplicates(List<string> array)
    {
        var dict = new Dictionary<string, int>();
        foreach (var value in array)
        {
            if (dict.ContainsKey(value))
                dict[value]++;
            else
                dict[value] = 1;
        }
        foreach (var pair in dict)
        {
            if (pair.Value > 1)
                return true;
            else
                return false;
        }
        return false;
    }
}  

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