2013-08-31 24 views

回答

317

解決問題的最簡單方法是根據元素的值對元素進行分組,然後在組中有多個元素時選擇該組的代表。在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(); 

這將返回一個匿名類型的列表,每個元素將具有元素和計數器的屬性,以檢索您需要的信息。

最後,如果它是你正在尋找一個字典,你可以使用

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

這將返回一個字典,用你的元素作爲重點,與時代它的重複值的數量。

+2

謝謝你,現在我很清楚LINQ是如何工作的,有一個愉快的一天。 –

+0

現在只是一個奇蹟,假設重複的int分佈到n個int數組中,我使用dictionary和for循環來理解哪個數組包含重複項並根據分佈邏輯將其刪除,是否有最快的方法(linq想知道)取得這樣的結果?預先感謝你的興趣。 –

+0

我做這樣的事情: 'code' 對(INT I = 0;我()); 對(INT K = 0; k

8

你可以這樣做:

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(); 
    } 
} 

在重複的方法使用IsMultiple()的速度更快,然後計數(),因爲這不遍歷整個集合。

+0

如果你看[分組的參考源](http://referencesource.microsoft.com/System.Core/System/Linq/Enumerable.cs.html#2177),你可以看到'Count()'**是**預先計算的,您的解決方案可能會更慢。 – Johnbot

+0

@Johnbot。你是對的,在這種情況下,它更快,實現可能永遠不會改變......但它取決於IGrouping背後的實現類的實現細節。用我的實現,你知道它永遠不會迭代整個集合。 –

+0

因此計數['Count()']與迭代整個列表基本上不同。 Count()是預先計算的,但是迭代整個列表不是。 – Jogi

13

另一種方法是使用HashSet

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

這裏是相同的解決方案作爲一種通用的擴展方法:

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); 
    } 
} 
+0

這不符合預期。使用'List {1,2,3,4,5,2}}作爲源,結果是一個「IEnumerable 」,其中一個元素的值爲「1」(其中正確的重複值爲2) – BCA

+0

@BCA昨天,我認爲你錯了。看看這個例子:https://dotnetfiddle.net/GUnhUl – HuBeZa

+0

你的小提琴打印出正確的結果。不過,我在其正下方添加了一行'Console.WriteLine(「Count:{0}」,duplicates.Count());',並且它打印了'6'。除非我錯過了這個函數的要求,否則結果集合中只應該有1個項目。 – BCA

69

瞭解是否可枚舉包含任何重複的

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

看看是否在枚舉所有獨特

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

謝謝,它正在工作 – Ilaria

6

我創建了一個extention來響應這個你可以includ它在你的項目,我認爲當您搜索列表或重複這個返回最案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 
     */ 
} 
+0

考慮使用Skip(1).Any()而不是Count()。如果您有1000個重複項,則Skip(1).Any()會在找到第二個重複項後停止。 Count()將訪問所有1000個元素。 –

+0

如果您添加此擴展方法,請考慮使用HashSet.Add而不是GroupBy,正如在其他答案中提到的那樣。只要HashSet.Add發現重複,它就會停止。您的GroupBy將繼續對所有元素進行分組,即使已找到具有多個元素的組 –

0

全套[重複] LINQ的擴展與MS SQL Server檢出的

public static class LinqExtensions { 

    public class CounterOfT<T> { 
     public T Key { get; set; } 
     public int Count { get; set; } 
    } 

    public static IQueryable<TKey> Duplicates<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> groupBy) where TSource : class 
     => source.GroupBy(groupBy).Where(w => w.Count() > 1).Select(s => s.Key).AsQueryable(); 

    public static IQueryable<TSource> GetDuplicates<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> groupBy) where TSource : class 
     => source.GroupBy(groupBy).Where(w => w.Count() > 1).SelectMany(s => s).AsQueryable(); 

    public static IQueryable<CounterOfT<TKey>> DuplicatesCounts<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> groupBy) where TSource : class 
     => source.GroupBy(groupBy).Where(w => w.Count() > 1).Select(y => new CounterOfT<TKey> { Key = y.Key, Count = y.Count() }).AsQueryable(); 

    public static IQueryable<Tuple<TKey, int>> DuplicatesCountsAsTuble<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> groupBy) where TSource : class 
    => source.GroupBy(groupBy).Where(w => w.Count() > 1).Select(s => Tuple.Create(s.Key, s.Count())).AsQueryable(); 

}