2012-10-24 99 views
-1

我要趕重複互斥互斥組,那就是,我要表明,無論是第一和第三項是重複的,而第一和第四的項目是重複的。通過LINQ的

public class Foo 
{ 
    public String Name { get; set; } 
    public String SName { get; set; } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     var list = new List<Foo>(); 
     list.Add(new Foo { Name = "a", SName = "d" }); 
     list.Add(new Foo { Name = "b", SName = "e" }); 
     list.Add(new Foo { Name = "c", SName = "a" }); 
     list.Add(new Foo { Name = "a", SName = "f" }); 

     // only groups by 1 name 
     var duplicates = list.GroupBy(i => i.Name).Where(g => g.Count() > 1).Select(g => g.Key); 
    } 
} 

我知道這可以用foreach輕鬆完成,我想學習。

+0

你的意思是你要考慮'Name'和'SName'爲e在比較方面是多少? –

+0

第三行你的意思是SName =「SName1」? –

+0

@FrédéricHamidi,是的。 – JoeB

回答

1

因此,我們將通過讓所有的重複名稱值從任一列開始了,這是相當容易:

IEnumerable<string> repeatedNames = list.SelectMany(foo => new[] { foo.Name, foo.SName }) 
    .GroupBy(name => name) 
    .Where (g => g.Count() > 1) 
    .Select(g => g.Key); 

接下來我們每一這些名稱並找到所有包含該項目的值。最終結果是每個不同名稱的序列,其中序列是包含該值的所有Foo項目。

IEnumerable<List<Foo>> groupings = repeatedNames .Select(name => 
    list.Where(foo => foo.Name == name || foo.SName == name).ToList()); 

如果你想要的,而不是FOOS,與兩個不同的值和序列的項目序列的列表的順序它是的話,那是很容易的添加:

var groupings = repeatedNames .Select(name => new 
    { 
     Name = name, 
     Foos = list.Where(foo => foo.Name == name || foo.SName == name).ToList() 
    }); 
+0

這很完美,謝謝。請注意,您可以使用以下內容作爲最後一項的快捷方式(我認爲,至少適用於我的方案):groupings.SelectMany(i => i) – JoeB

+0

@JoeBehymer在這種特殊情況下,「a」是唯一的名稱重複,所以只有一個列表。如果有3個Foos有「a」,兩個有「b」,那麼問題是你想要所有的'Foo'項目都帶有「a」還是「b」,或者你想要一個列表「a」和「b」的列表。我編碼後者。 – Servy

+0

哦,我明白了。對於我的情況,後者是好的。再次感謝。 – JoeB

0

如果你只是想是重複的,而不是它們出現在該指標的值,那麼你可以使用SelectMany的名稱轉換成字符串的一個列表做分組之前:

var duplicates2 = list.SelectMany(n => new string[] {n.Name, n.SName}) 
         .GroupBy(g => g) 
         .Where (g => g.Count() > 1) 
         .Select(g => g.Key) 
         .ToList(); 

編輯: 如果你想Foo對象,而不只是字符串,你可以這樣選擇它們:

var duplicates3 = list.Where(n => duplicates2.Contains(n.Name) || 
            duplicates2.Contains(n.SName)); 
+0

這給出了重複的所有名稱,而不是所有重複的每個名稱的Foos。途中有一半 – Servy

+0

@Servy謝謝。我編輯了我的答案以包含此內容。 –

0

我想出了這一點:

// Will return "a" - one which you already had 
var duplicatesBetweenNames = list.GroupBy(i => i.Name) 
    .Where(g => g.Count() > 1) 
    .Select(g => g.Key).ToArray(); 

var duplicatedInSName = list.Select(x => x.Name) 
    .Intersect(list.Select(x => x.SName)); 
// Will return "c" - represents Names where in SName is duplicate 
var duplicatesBetweenNameAndSName = list 
    .Where(f => duplicatedInSName.Contains(f.SName)) 
    .Select(x=>x.Name).ToArray(); 
0

有趣的線索,我只是認爲查詢語法是在這種情況下,很有表現力:

var r = from l in list 
     from s in new [] {l.Name,l.SName} 
     group s by s into g 
     where g.Count() > 1 
     select g.Key into u 
     from l in list 
     where u.Contains(l.Name) || u.Contains(l.SName) 
     select l;