【发布时间】:2013-08-31 10:55:22
【问题描述】:
使用 LINQ,从 List<int>,我如何检索包含重复多次的条目及其值的列表?
【问题讨论】:
标签: linq list duplicate-removal
使用 LINQ,从 List<int>,我如何检索包含重复多次的条目及其值的列表?
【问题讨论】:
标签: linq list duplicate-removal
解决问题的最简单方法是根据元素的值对元素进行分组,如果组中有多个元素,则选择该组的代表。在 LINQ 中,这转换为:
var query = lst.GroupBy(x => x)
.Where(g => g.Count() > 1)
.Select(y => y.Key)
.ToList();
如果想知道元素重复了多少次,可以使用:
var query = lst.GroupBy(x => x)
.Where(g => g.Count() > 1)
.Select(y => new { Element = y.Key, Counter = y.Count() })
.ToList();
这将返回一个匿名类型的List,每个元素将具有Element 和Counter 属性,以检索您需要的信息。
最后,如果您要查找的是字典,则可以使用
var query = lst.GroupBy(x => x)
.Where(g => g.Count() > 1)
.ToDictionary(x => x.Key, y => y.Count());
这将返回一个字典,其中您的元素作为键,重复的次数作为值。
【讨论】:
code for (int i = 0; i ()); for (int k = 0; k code
找出一个可枚举项是否包含任何重复项:
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));
如果您希望重复列表中的唯一值:
var myhash = new HashSet<int>();
var mylist = new List<int>(){1,1,2,2,3,3,3,4,4,4};
var duplicates = mylist.Where(item => !myhash.Add(item)).Distinct().ToList();
这里是与通用扩展方法相同的解决方案:
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);
}
}
【讨论】:
List<int> { 1, 2, 3, 4, 5, 2 } 作为源,结果是一个IEnumerable<int>,其中一个元素的值为1(其中正确的重复值为2)
Console.WriteLine("Count: {0}", duplicates.Count()); 行,它打印了6。除非我遗漏了有关此功能的要求,否则结果集合中应该只有 1 项。
ToList 以解决此问题,但这意味着该方法在调用后立即执行,而不是在您迭代结果时执行。
var hash = new HashSet<int>(); var duplicates = list.Where(i => !hash.Add(i)); 将生成一个包含所有重复项的列表。因此,如果您的列表中有 4 个 2,那么您的重复列表将包含 3 个 2,因为只有一个 2 可以添加到 HashSet。如果您希望列表包含每个重复项的唯一值,请改用此代码:var duplicates = mylist.Where(item => !myhash.Add(item)).ToList().Distinct().ToList();
仅查找重复值:
var duplicates = list.GroupBy(x => x.Key).Any(g => g.Count() > 1);
例如
var list = new[] {1,2,3,1,4,2};
GroupBy 将按它们的键对数字进行分组,并保持计数(重复的次数)。之后,我们只是检查重复多次的值。
仅查找唯一值:
var unique = list.GroupBy(x => x.Key).All(g => g.Count() == 1);
例如
var list = new[] {1,2,3,1,4,2};
GroupBy 将按它们的键对数字进行分组,并保持计数(重复的次数)。之后,我们只是检查仅重复一次的值意味着是唯一的。
【讨论】:
var unique = list.Distinct(x => x)
你可以这样做:
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 moreThan1 = grouped.Where(i => i.IsMultiple());
return moreThan1.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() 更快,因为这不会迭代整个集合。
【讨论】:
Count() 是预先计算的,您的解决方案可能会更慢。
Count()] 与迭代整个列表基本上不同。 Count() 是预先计算的,但不是迭代整个列表。
我创建了一个扩展来响应这个问题,你可以将它包含在你的项目中,我认为当你在 List 或 Linq 中搜索重复项时,这会返回大多数情况。
例子:
//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
*/
}
【讨论】:
有一个答案,但我不明白为什么不起作用;
var anyDuplicate = enumerable.GroupBy(x => x.Key).Any(g => g.Count() > 1);
在这种情况下我的解决方案是这样的;
var duplicates = model.list
.GroupBy(s => s.SAME_ID)
.Where(g => g.Count() > 1).Count() > 0;
if(duplicates) {
doSomething();
}
【讨论】:
在 MS SQL Server 中检查了 Duplicates 函数的完整 Linq to SQL 扩展集。不使用 .ToList() 或 IEnumerable。 这些查询在 SQL Server 中而不是在内存中执行。。结果只在内存中返回。
public static class Linq2SqlExtensions {
public class CountOfT<T> {
public T Key { get; set; }
public int Count { get; set; }
}
public static IQueryable<TKey> Duplicates<TSource, TKey>(this IQueryable<TSource> source, Expression<Func<TSource, TKey>> groupBy)
=> source.GroupBy(groupBy).Where(w => w.Count() > 1).Select(s => s.Key);
public static IQueryable<TSource> GetDuplicates<TSource, TKey>(this IQueryable<TSource> source, Expression<Func<TSource, TKey>> groupBy)
=> source.GroupBy(groupBy).Where(w => w.Count() > 1).SelectMany(s => s);
public static IQueryable<CountOfT<TKey>> DuplicatesCounts<TSource, TKey>(this IQueryable<TSource> source, Expression<Func<TSource, TKey>> groupBy)
=> source.GroupBy(groupBy).Where(w => w.Count() > 1).Select(y => new CountOfT<TKey> { Key = y.Key, Count = y.Count() });
public static IQueryable<Tuple<TKey, int>> DuplicatesCountsAsTuble<TSource, TKey>(this IQueryable<TSource> source, Expression<Func<TSource, TKey>> groupBy)
=> source.GroupBy(groupBy).Where(w => w.Count() > 1).Select(s => Tuple.Create(s.Key, s.Count()));
}
【讨论】:
Linq 查询:
var query = from s2 in (from s in someList group s by new { s.Column1, s.Column2 } into sg select sg) where s2.Count() > 1 select s2;
【讨论】:
这种不使用组的更简单方法只需获取 District 元素,然后遍历它们并检查它们在列表中的计数,如果它们的 计数>1,这意味着出现超过 1 个项目,因此将其添加到 Repeteditemlist
var mylist = new List<int>() { 1, 1, 2, 3, 3, 3, 4, 4, 4 };
var distList= mylist.Distinct().ToList();
var Repeteditemlist = new List<int>();
foreach (var item in distList)
{
if(mylist.Count(e => e == item) > 1)
{
Repeteditemlist.Add(item);
}
}
foreach (var item in Repeteditemlist)
{
Console.WriteLine(item);
}
预期输出:
1 3 4
【讨论】:
按键删除重复项
myTupleList = myTupleList.GroupBy(tuple => tuple.Item1).Select(group => group.First()).ToList();
【讨论】: