【问题标题】:C# Determine Duplicate in List [duplicate]C#确定列表中的重复项[重复]
【发布时间】:2011-02-22 15:59:45
【问题描述】:

要求:在一个未排序的List中,判断是否存在重复。我会这样做的典型方法是 n 平方嵌套循环。我想知道其他人如何解决这个问题。 Linq 中是否有优雅、高性能的方法?采用 lambda 或比较器的通用东西会很好。

【问题讨论】:

  • 我记得以前在这里看到过这个问题,人们提出了一些巧妙的技巧,但我不记得它是什么了......等等...... jon skeet 在附近
  • 您的问题似乎已经得到解答,您应该相应地标记它,如果不满意您可以编辑您的问题以更清楚地解释它。 ;)

标签: c# linq algorithm list generics


【解决方案1】:

除非我遗漏了什么,否则你应该可以使用Distinct() 来解决一些简单的问题。当然,它不会是您能想到的最复杂的实现,但它会告诉您是否删除了任何重复项:

var list = new List<string>();

// Fill the list

if(list.Count != list.Distinct().Count())
{
     // Duplicates exist
}

【讨论】:

  • + 1 如果我没记错的话Distinct() 在内部使用哈希表,所以应该是 O(n)
  • 不要调用 list.Count() 方法。请改用 Count 属性。我知道 LINQ 已经过优化,它会在内部使用它,但我仍然认为使用该属性会更好。
  • 这实际上是我的第一个想法。感谢 BrokenGlass 确认 Distinct() 为 O(n)。
  • @PetarPetrov - 关于.Count.Count() 我需要使用.Count()。如果我不这样做,则会收到一条错误消息,指出 Operator '!=' cannot be applied to 'method group' 和 'method group' 类型的操作数
  • 当您访问列表 3 次时,此解决方案似乎并不快。我会考虑向 HasSet 添加元素,直到它返回 false。
【解决方案2】:

根据Eric White关于如何Find Duplicates using LINQ的文章:

查找重复项的一种简单方法是编写一个按标识符分组的查询,然后过滤具有多个成员的组。在下面的例子中,我们想知道 4 和 3 是重复的:

int[] listOfItems = new[] { 4, 2, 3, 1, 6, 4, 3 };
var duplicates = listOfItems
    .GroupBy(i => i)
    .Where(g => g.Count() > 1)
    .Select(g => g.Key);
foreach (var d in duplicates)
    Console.WriteLine(d); // 4,3

【讨论】:

  • 这肯定会起作用,但需要的时间比必要的要长(OP 只需要知道是否存在重复项......而不是重复值是什么)。
  • 如果您需要知道重复值是什么,这会更有帮助。
  • 谷歌第一次找到我的问题。这里绝对是一个很棒的信息
【解决方案3】:

如果重复项存在于列表的前面,为了允许短路,您可以添加HashSet&lt;T&gt; 并检查其.Add 方法的返回值。

通过使用.Any,您可以在发现重复项后立即将枚举短路。

这是 C# 和 VB 中的 LINQ 扩展方法:

CSharp:

public static bool ContainsDuplicates<T>(this IEnumerable<T> enumerable)
{
    var knownKeys = new HashSet<T>();
    return enumerable.Any(item => !knownKeys.Add(item));
}

Visual Basic:

<Extension>
Public Function ContainsDuplicates(Of T)(ByVal enumerable As IEnumerable(Of T)) As Boolean
    Dim knownKeys As New HashSet(Of T)
    Return enumerable.Any(Function(item) Not knownKeys.Add(item))
End Function

注意:要检查是否有没有重复,只需将Any更改为All

【讨论】:

  • 这很好很优雅,类似于described here 也返回重复的方法。
【解决方案4】:

将所有项目放在一个集合中,如果集合的计数与列表的计数不同,则存在重复。

bool hasDuplicates<T>(List<T> myList) {
    var hs = new HashSet<T>();

    for (var i = 0; i < myList.Count; ++i) {
        if (!hs.Add(myList[i])) return true;
    }
    return false;
}

应该比 Distinct 更有效,因为不需要遍历所有列表。

【讨论】:

  • 不要调用 list.Count() 方法。请改用 Count 属性。我知道 LINQ 已经过优化,它会在内部使用它,但我仍然认为使用该属性会更好。
  • 承认如果有重复项会更有效。但如果没有重复,那么它会做同样多的工作。使用哪一个可能取决于“正常”情况是否没有重复。
  • @Petar Petrov:好点。可能应该只使用foreach。并使参数IEnumerable&lt;T&gt; 而不是List&lt;T&gt;
【解决方案5】:

这些方面的东西相对简单,并且会为您提供重复的计数。

var something = new List<string>() { "One", "One", "Two", "Three" };

var dictionary = new Dictionary<string, int>();

something.ForEach(s =>
    {
        if (dictionary.ContainsKey(s))
        {
            dictionary[s]++;
        }
        else
        {
            dictionary[s] = 1;
        }
    });

我想这类似于 Distinct 的实现,虽然我不确定。

【讨论】:

  • HashSet 似乎更易于使用。
  • 是的,这确实更有意义。
  • @Trinidad:但不会给你计数
  • @recursive,这不是问题的一部分。请参阅:在未排序的 List 中,确定是否存在重复项
  • 这是完美的,因为我是 C# 新手,需要一些东西来跟踪一组值中每个实例的计数(例如,从 http 资源中提取的 20,000 多个文件名),我想在可能覆盖具有重复文件名的文件之前知道是否存在任何重复项。字典是我正在考虑的,所以看到这里推荐它是令人振奋的。
【解决方案6】:

您可以使用 IEnumerable.GroupBy 方法。

var list = new List<string> {"1", "2","3", "1", "2"};
var hasDuplicates = list.GroupBy(x => x).Any(x => x.Skip(1).Any());

【讨论】:

    【解决方案7】:

    您可以对 IEnumerable 使用 Distinct() 扩展方法

    【讨论】:

      【解决方案8】:

      如果您使用整数或有序集合,请使用二叉树以获得 O(nlog n) 性能。

      或者,找到另一种更快的排序方式,然后简单地检查每个值是否与前一个不同。

      【讨论】:

        【解决方案9】:

        Enumerable.AnyHashSet.Add 一起使用,例如:

        List<string> list = new List<string> {"A", "A", "B", "C", "D"};
        HashSet<string> hashSet = new HashSet<string>();
        if(list.Any(r => !hashSet.Add(r)))
        {
           //duplicate exists. 
        }
        

        如果HashSet 中已经存在该项目,HashSet.Add 将返回false。这不会迭代整个列表。

        【讨论】:

          【解决方案10】:

          您可以使用Distinct() 语句来查找唯一记录。然后与这样的原始通用列表进行比较:

            if (dgCoil.ItemsSource.Cast<BLL.Coil>().ToList().Count != dgCoil.ItemsSource.Cast<BLL.Coil>().Select(c => c.CoilNo).Distinct().Count())
            {    
              //Duplicate detected !!
              return;
            }
          

          【讨论】:

            【解决方案11】:

            还没有看到有人这样做,所以这是我刚刚编写的一个小程序。这很简单。使用 Contains(),虽然我不知道这种方法的可扩展性如何。

                   Console.WriteLine("Please enter 5 unique numbers....");
                    List<int> uniqueNums = new List<int>() { };
                    while (uniqueNums.Count < 5)
                    {
                        int input = Convert.ToInt32(Console.ReadLine());
                        if (uniqueNums.Contains(input))
                        {
                            Console.WriteLine("Add a different number");
                        }
                        uniqueNums.Add(input);
                    }
                    uniqueNums.Sort();
                    foreach (var n in uniqueNums)
                    {
                        Console.WriteLine(n);
                    }
            

            【讨论】:

            • 恕我直言,我认为您的回答没有回答问题。我知道这个问题是关于,给定一个已经存在的列表..找出一个重复的。您正在建议一种手动填充列表的方法,即在插入副本时通过在线输出。您还将列表命名为 uniquelist 但您允许重复插入,我认为这不是您的意图(小错误)。我说的对吗?
            • 编辑:找出重复项,-> .. 找出是否包含重复项:-)
            • 我明白你的意思,但是在做那个小练习时(我不是专家,这是我正在做的课程的一部分),我在寻找一种方法来确定是否输入将是列表中的重复项。因此,答案代表可能不太清楚自己在寻找什么的其他人。我在研究时找不到答案“if (uniqueNums.Contains(input))”,所以也许这可能会帮助其他人在编码生活的早期阶段! :-) 这可能会回答您的另一个问题,是的,输入没有被阻止,这不是练习的一部分。
            • 明白你的意思,但我仍然认为这是错误的。如果一个问题与答案不完全吻合(你有),最好创建一个新问题(为你的答案)并简单地自我回答你的同一个问题。这是一种完全合法的做事方式。此外,由于这个问题不同,人们很难找到针对不同问题的代码 sn-p。在您的情况下,也许一篇小型博客文章更有意义。但这只是我的意见。最后一句话:有时写出不符合问题的答案,你可能会被否决。问候
            猜你喜欢
            • 2022-11-30
            • 2013-09-25
            • 2012-05-29
            • 1970-01-01
            • 1970-01-01
            • 2020-01-24
            • 2023-04-08
            • 2015-10-04
            • 1970-01-01
            相关资源
            最近更新 更多