33

我正在寻找一种非常快速的方法来检查对象列表中的重复项。

我正在考虑简单地遍历列表并以这种方式进行手动比较,但我认为 linq 可能会提供更优雅的解决方案......

假设我有一个对象...

public class dupeCheckee
{
     public string checkThis { get; set; }
     public string checkThat { get; set; }

     dupeCheckee(string val, string val2)
     {
         checkThis = val;
         checkThat = val2;
     }
}

我有这些对象的列表

List<dupeCheckee> dupList = new List<dupeCheckee>();
dupList.Add(new dupeCheckee("test1", "value1"));
dupList.Add(new dupeCheckee("test2", "value1"));
dupList.Add(new dupeCheckee("test3", "value1"));
dupList.Add(new dupeCheckee("test1", "value1"));//dupe
dupList.Add(new dupeCheckee("test2", "value1"));//dupe... 
dupList.Add(new dupeCheckee("test4", "value1"));
dupList.Add(new dupeCheckee("test5", "value1"));
dupList.Add(new dupeCheckee("test1", "value2"));//not dupe

我需要在该列表中找到受骗者。当我找到它时,我需要做一些额外的逻辑,不一定要删除它们。

当我使用 linq 时,我的 GroupBy 如何抛出异常......

'System.Collections.Generic.List<dupeCheckee>' does not contain a definition for 'GroupBy' and no extension method 'GroupBy' accepting a first argument of type 'System.Collections.Generic.List<dupeCheckee>' could be found (are you missing a using directive or an assembly reference?)

这告诉我我错过了一个图书馆。我很难弄清楚是哪一个。

但是,一旦我弄清楚了,我将如何检查这两个条件... IE checkThis 和 checkThat 都发生了不止一次?

更新:我想出了什么

这是我在进行快速研究后提出的 linq 查询......

test.Count != test.Select(c => new { c.checkThat, c.checkThis }).Distinct().Count()

我不确定这是否肯定比这个答案更好......

var duplicates = test.GroupBy(x => new {x.checkThis, x.checkThat})
                   .Where(x => x.Skip(1).Any());

我知道我可以将第一条语句放入 if else 子句中。我还进行了快速测试。当我期待 0 时,重复列表给了我 1,但它确实正确地说明了我在我使用的其中一个集合中有重复的事实......

另一种方法完全符合我的预期。这是我用来测试的数据集....

骗子:

List<DupeCheckee> test = new List<DupeCheckee>{ 
     new DupeCheckee("test0", "test1"),//{ checkThis = "test", checkThat = "test1"}
     new DupeCheckee("test1", "test2"),//{ checkThis = "test", checkThat = "test1"}
     new DupeCheckee("test2", "test3"),//{ checkThis = "test", checkThat = "test1"}
     new DupeCheckee("test3", "test3"),//{ checkThis = "test", checkThat = "test1"}
     new DupeCheckee("test0", "test5"),//{ checkThis = "test", checkThat = "test1"}
     new DupeCheckee("test1", "test6"),//{ checkThis = "test", checkThat = "test1"}
     new DupeCheckee("test2", "test7"),//{ checkThis = "test", checkThat = "test1"}
     new DupeCheckee("test3", "test8"),//{ checkThis = "test", checkThat = "test1"}
     new DupeCheckee("test0", "test5"),//{ checkThis = "test", checkThat = "test1"}
     new DupeCheckee("test1", "test1"),//{ checkThis = "test", checkThat = "test1"}
     new DupeCheckee("test2", "test2"),//{ checkThis = "test", checkThat = "test1"}
     new DupeCheckee("test3", "test3"),//{ checkThis = "test", checkThat = "test1"}
     new DupeCheckee("test4", "test4"),//{ checkThis = "test", checkThat = "test1"}

};

没有骗子...

     List<DupeCheckee> test2 = new List<DupeCheckee>{ 
     new DupeCheckee("test0", "test1"),//{ checkThis = "test", checkThat = "test1"}
     new DupeCheckee("test1", "test2"),//{ checkThis = "test", checkThat = "test1"}
     new DupeCheckee("test2", "test3"),//{ checkThis = "test", checkThat = "test1"}
     new DupeCheckee("test3", "test3"),//{ checkThis = "test", checkThat = "test1"}
     new DupeCheckee("test4", "test5"),//{ checkThis = "test", checkThat = "test1"}
     new DupeCheckee("test5", "test6"),//{ checkThis = "test", checkThat = "test1"}
     new DupeCheckee("test6", "test7"),//{ checkThis = "test", checkThat = "test1"}
     new DupeCheckee("test7", "test8"),//{ checkThis = "test", checkThat = "test1"}
     new DupeCheckee("test8", "test5"),//{ checkThis = "test", checkThat = "test1"}
     new DupeCheckee("test9", "test1"),//{ checkThis = "test", checkThat = "test1"}
     new DupeCheckee("test2", "test2"),//{ checkThis = "test", checkThat = "test1"}
     new DupeCheckee("test3", "test3"),//{ checkThis = "test", checkThat = "test1"}
     new DupeCheckee("test4", "test4"),//{ checkThis = "test", checkThat = "test1"}

};
4

7 回答 7

57

您需要参考 System.Linq (例如using System.Linq

那么你可以做

var dupes = dupList.GroupBy(x => new {x.checkThis, x.checkThat})
                   .Where(x => x.Skip(1).Any());

这将为您提供包含所有重复项的组

重复的测试将是

var hasDupes = dupList.GroupBy(x => new {x.checkThis, x.checkThat})
                   .Where(x => x.Skip(1).Any()).Any();

甚至调用ToList()ToArray()强制计算结果,然后您可以检查是否有欺骗性并检查它们。

例如..

var dupes = dupList.GroupBy(x => new {x.checkThis, x.checkThat})
                   .Where(x => x.Skip(1).Any()).ToArray();
if (dupes.Any()) {
  foreach (var dupeList in dupes) {
    Console.WriteLine(string.Format("checkThis={0},checkThat={1} has {2} duplicates",
                      duplist.Key.checkThis, 
                      duplist.Key.checkThat,
                      duplist.Count() - 1));
  }

}

或者

var dupes = dupList.Select((x, i) => new { index = i, value = x})
                   .GroupBy(x => new {x.value.checkThis, x.value.checkThat})
                   .Where(x => x.Skip(1).Any());

它为您提供了组,每个组的每个项目将原始索引存储在属性index中,并将项目存储在属性中value

于 2013-04-24T16:36:10.800 回答
13

有大量可行的解决方案,但我认为下一个解决方案将更加透明和易于理解,然后以上:

var hasDuplicatedEntries = ListWithPossibleDuplicates
                                   .GroupBy(YourGroupingExpression)
                                   .Any(e => e.Count() > 1);
if(hasDuplicatedEntries)
{
   // Do what ever you want in case when list contains duplicates 
}
于 2016-05-02T17:48:23.520 回答
3

我喜欢用它来知道什么时候有任何重复。假设您有一个字符串并想知道是否有任何重复的字母。这就是我使用的。

string text = "this is some text";

var hasDupes = text.GroupBy(x => x).Any(grp => grp.Count() > 1);

如果您想知道有多少重复项,无论重复项是什么,请使用它。

var totalDupeItems = text.GroupBy(x => x).Count(grp =>  grp.Count() > 1);

例如,“这是一些文本”有这个......

字母 t 总数:3

字母 i 总数:2

字母 s 总数:3

字母 e 总数:2

所以变量 totalDupeItems 等于 4。有 4 种不同的重复项。

如果您想获得无论是什么骗子的骗子项目的总数,请使用它。

var totalDupes = letters.GroupBy(x => x).Where(grp => grp.Count() > 1).Sum(grp => grp.Count());

所以变量 totalDupes 将是 10。这是每个欺骗类型的总重复项加在一起。

于 2015-03-12T16:12:23.877 回答
1

我想这就是你要找的:

List<dupeChecke> duplicates = dupeList.GroupBy(x => x)
                                   .SelectMany(g => g.Skip(1));
于 2013-04-24T16:36:29.357 回答
1

对于内存对象,我总是使用DistinctLINQ 方法将比较器添加到解决方案中。

public class dupeCheckee
{
     public string checkThis { get; set; }
     public string checkThat { get; set; }

     dupeCheckee(string val, string val2)
     {
         checkThis = val;
         checkThat = val2;
     }

     public class Comparer : IEqualityComparer<dupeCheckee>
     {
         public bool Equals(dupeCheckee x, dupeCheckee y)
         {
             if (x == null || y == null)
                 return false;

             return x.CheckThis == y.CheckThis && x.CheckThat == y.CheckThat;
         }

         public int GetHashCode(dupeCheckee obj)
         {
             if (obj == null)
                 return 0;

             return (obj.CheckThis == null ? 0 : obj.CheckThis.GetHashCode()) ^
                 (obj.CheckThat == null ? 0 : obj.CheckThat.GetHashCode());
         }
     }
}

现在我们可以调用

List<dupeCheckee> dupList = new List<dupeCheckee>();
dupList.Add(new dupeCheckee("test1", "value1"));
dupList.Add(new dupeCheckee("test2", "value1"));
dupList.Add(new dupeCheckee("test3", "value1"));
dupList.Add(new dupeCheckee("test1", "value1"));//dupe
dupList.Add(new dupeCheckee("test2", "value1"));//dupe... 
dupList.Add(new dupeCheckee("test4", "value1"));
dupList.Add(new dupeCheckee("test5", "value1"));
dupList.Add(new dupeCheckee("test1", "value2"));//not dupe

var distinct = dupList.Distinct(dupeCheckee.Comparer);
于 2013-04-24T18:35:17.867 回答
0

使用 linq 进行选择不同,例如如何使用 LINQ 进行 SELECT UNIQUE?

然后将不同结果的计数与非不同结果进行比较。如果列表有双打,这会给你一个布尔值。

此外,您可以尝试使用字典,这将保证密钥是唯一的。

于 2013-04-24T16:29:37.487 回答
0

如果发生任何重复将引发异常。字典自己检查键。这是最简单的方法。

try
{
  dupList.ToDictionary(a=>new {a.checkThis,a.checkThat});
}
catch{
 //message: list items is not uniqe
}
于 2016-08-16T12:23:10.450 回答