C#LINQ在List中查找重复项

使用LINQ,从一个List<int> ,我如何检索一个包含多次重复的条目和它们的值的列表?

解决问题最简单的方法是根据元素的值对元素进行分组,如果组中有多个元素,则select该组的代表。 在linq中,这转化为:

 var query = lst.GroupBy(x=>x) .Where(g=>g.Count()>1) .Select(y=>y.Key) .ToList(); 

如果你想知道元素重复了多less次,你可以使用:

 var query = lst.GroupBy(x=>x) .Where(g=>g.Count()>1) .Select(y=> new { Element = y.Key, Counter = y.Count()}) .ToList(); 

这将返回一个匿名types的列表,每个元素将有属性Element和Counter,来检索你需要的信息。

最后,如果它是你正在寻找的字典,你可以使用

 var query = lst.GroupBy(x=>x) .Where(g=>g.Count()>1) .ToDictionary(x=>x.Key,y=>y.Count()); 

这将返回一个字典,以您的元素作为关键字,以及作为值重复的次数。

找出一个枚举是否包含任何重复

 var anyDuplicate = enumerable.GroupBy(x => x.Key).Any(g => g.Count() > 1); 

找出一个枚举中的所有值是否唯一

 var allUnique = enumerable.GroupBy(x => x.Key).All(g => g.Count() == 1); 

另一种方法是使用HashSet

 var hash = new HashSet<int>(); var duplicates = list.Where(i => !hash.Add(i)); 

这是一个通用的扩展方法相同的解决scheme:

 public static class Extensions { public static IEnumerable<TSource> GetDuplicates<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> selector, IEqualityComparer<TKey> comparer) { var hash = new HashSet<TKey>(comparer); return source.Where(item => !hash.Add(selector(item))).ToList(); } public static IEnumerable<TSource> GetDuplicates<TSource>(this IEnumerable<TSource> source, IEqualityComparer<TSource> comparer) { return source.GetDuplicates(x => x, comparer); } public static IEnumerable<TSource> GetDuplicates<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> selector) { return source.GetDuplicates(selector, null); } public static IEnumerable<TSource> GetDuplicates<TSource>(this IEnumerable<TSource> source) { return source.GetDuplicates(x => x, null); } } 

你可以这样做:

 var list = new[] {1,2,3,1,4,2}; var duplicateItems = list.Duplicates(); 

有了这些扩展方法:

 public static class Extensions { public static IEnumerable<TSource> Duplicates<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> selector) { var grouped = source.GroupBy(selector); var moreThen1 = grouped.Where(i => i.IsMultiple()); return moreThen1.SelectMany(i => i); } public static IEnumerable<TSource> Duplicates<TSource, TKey>(this IEnumerable<TSource> source) { return source.Duplicates(i => i); } public static bool IsMultiple<T>(this IEnumerable<T> source) { var enumerator = source.GetEnumerator(); return enumerator.MoveNext() && enumerator.MoveNext(); } } 

在Duplicates方法中使用IsMultiple()比Count()更快,因为这不会迭代整个集合。

我创build了一个扩展来响应这个,你可以包括在你的项目中,我想这会返回大多数情况下,当你在List或Linqsearch重复。

例:

 //Dummy class to compare in list public class Person { public int Id { get; set; } public string Name { get; set; } public string Surname { get; set; } public Person(int id, string name, string surname) { this.Id = id; this.Name = name; this.Surname = surname; } } //The extention static class public static class Extention { public static IEnumerable<T> getMoreThanOnceRepeated<T>(this IEnumerable<T> extList, Func<T, object> groupProps) where T : class { //Return only the second and next reptition return extList .GroupBy(groupProps) .SelectMany(z => z.Skip(1)); //Skip the first occur and return all the others that repeats } public static IEnumerable<T> getAllRepeated<T>(this IEnumerable<T> extList, Func<T, object> groupProps) where T : class { //Get All the lines that has repeating return extList .GroupBy(groupProps) .Where(z => z.Count() > 1) //Filter only the distinct one .SelectMany(z => z);//All in where has to be retuned } } //how to use it: void DuplicateExample() { //Populate List List<Person> PersonsLst = new List<Person>(){ new Person(1,"Ricardo","Figueiredo"), //fist Duplicate to the example new Person(2,"Ana","Figueiredo"), new Person(3,"Ricardo","Figueiredo"),//second Duplicate to the example new Person(4,"Margarida","Figueiredo"), new Person(5,"Ricardo","Figueiredo")//third Duplicate to the example }; Console.WriteLine("All:"); PersonsLst.ForEach(z => Console.WriteLine("{0} -> {1} {2}", z.Id, z.Name, z.Surname)); /* OUTPUT: All: 1 -> Ricardo Figueiredo 2 -> Ana Figueiredo 3 -> Ricardo Figueiredo 4 -> Margarida Figueiredo 5 -> Ricardo Figueiredo */ Console.WriteLine("All lines with repeated data"); PersonsLst.getAllRepeated(z => new { z.Name, z.Surname }) .ToList() .ForEach(z => Console.WriteLine("{0} -> {1} {2}", z.Id, z.Name, z.Surname)); /* OUTPUT: All lines with repeated data 1 -> Ricardo Figueiredo 3 -> Ricardo Figueiredo 5 -> Ricardo Figueiredo */ Console.WriteLine("Only Repeated more than once"); PersonsLst.getMoreThanOnceRepeated(z => new { z.Name, z.Surname }) .ToList() .ForEach(z => Console.WriteLine("{0} -> {1} {2}", z.Id, z.Name, z.Surname)); /* OUTPUT: Only Repeated more than once 3 -> Ricardo Figueiredo 5 -> Ricardo Figueiredo */ }