2011-01-02 8 views
82

私はList<string>にいくつかの単語が重複しています。私は重複するすべての単語を見つける必要があります。リストからすべての重複を見つける方法<string>?

これらのすべてを得るにはどんなトリックですか?

+0

可能複製[使用してリストから重複した項目を取得する方法LINQ?](http://stackoverflow.com/questions/3811464/how-to-get-duplicate-items-from-a-list-using-linq) – nawfal

+1

@nawfal私はLinqがここに記載されているのを見ません... – rene

答えて

148

単一列挙まで戻って取得:

var duplicateKeys = list.GroupBy(x => x) 
         .Where(group => group.Count() > 1) 
         .Select(group => group.Key); 
+3

これは、すべての行をdではなく値でグループ化しますuplicates ...あなたはまだ 'Count()> 1'でフィルタリングする必要があります。また、質問を理解する方法は、各行にいくつかの単語が含まれていて、OPは重複した単語を望んでいます(おそらく私はその質問を誤解しました)。 –

+31

@Thomas:はい、コードは完全ではなく、そして、 'list.GroupBy(x => x).Where(group => group.Count()> 1)のように、重複だけを望むなら' Where'を使うことができます。(group => Group.Key).ToList()を選択してください。 –

3

あなたのリストの各文字列に複数の単語が含まれていると仮定していますが、それが間違っているかどうか教えてください。 、その後に自分のキーを選択し、.NETフレームワーク3.5では、あなたが重複キーのenumerablesの列挙を返しEnumerable.GroupByを使用して、< = 1のカウントを持っているenumerablesのいずれかを除外することができます上記

List<string> list = File.RealAllLines("foobar.txt").ToList(); 

var words = from line in list 
      from word in line.Split(new[] { ' ', ';', ',', '.', ':', '(', ')' }, StringSplitOptions.RemoveEmptyEntries) 
      select word; 

var duplicateWords = from w in words 
        group w by w.ToLower() into g 
        where g.Count() > 1 
        select new 
        { 
         Word = g.Key, 
         Count = g.Count() 
        } 
17

やLINQなし:LINQを使用して

string[] ss = {"1","1","1"}; 

var myList = new List<string>(); 
var duplicates = new List<string>(); 

foreach (var s in ss) 
{ 
    if (!myList.Contains(s)) 
     myList.Add(s); 
    else 
     duplicates.Add(s); 
} 

// show list without duplicates 
foreach (var s in myList) 
    Console.WriteLine(s); 

// show duplicates list 
foreach (var s in duplicates) 
    Console.WriteLine(s); 
+0

なぜオーバーヘッドなしで宣言できたらvarを使用しますか? – BKSpurgeon

+0

「var」に「オーバーヘッド」はありません。 –

5

、ofcourseの。 以下のコードは、itemの辞書を文字列として、そしてあなたのソースリストの各項目の数を示します。

List<string> list = new List<string>(new string[] { "cat", "Dog", "parrot", "dog", "parrot", "goat", "parrot", "horse", "goat" }); 
Dictionary<string, int> wordCount = new Dictionary<string, int>(); 

//count them all: 
list.ForEach(word => 
{ 
    string key = word.ToLower(); 
    if (!wordCount.ContainsKey(key)) 
     wordCount.Add(key, 0); 
    wordCount[key]++; 
}); 

//remove words appearing only once: 
wordCount.Keys.ToList().FindAll(word => wordCount[word] == 1).ForEach(key => wordCount.Remove(key)); 

Console.WriteLine(string.Format("Found {0} duplicates in the list:", wordCount.Count)); 
wordCount.Keys.ToList().ForEach(key => Console.WriteLine(string.Format("{0} appears {1} times", key, wordCount[key]))); 
2

シンタック糖なし:

var duplicateItems = list.GroupBy(x => x).Where(x => x.Count() > 1).Select(x => x.Key); 

これは、同じ要素をすべてグループ化し、複数の要素を持つグループのみにフィルタリングします。最後に、カウントを必要としないので、これらのグループからキーを選択します。

あなたはLINQを使用しない場合は、あなたはこの拡張メソッドを使用することができます。

public void SomeMethod { 
    var duplicateItems = list.GetDuplicates(); 
    … 
} 

public static IEnumerable<T> GetDuplicates<T>(this IEnumerable<T> source) { 
    HashSet<T> itemsSeen = new HashSet<T>(); 
    HashSet<T> itemsYielded = new HashSet<T>(); 

    foreach (T item in source) { 
     if (!itemsSeen.Add(item)) { 
      if (itemsYielded.Add(item)) { 
       yield return item; 
      } 
     } 
    } 
} 

これは見てもたらしたアイテムを追跡します。以前にアイテムを見たことがなければ、それを表示されたアイテムのリストに追加します。それ以外の場合は無視します。以前にアイテムを生成していない場合はそれを返し、それ以外の場合は無視します。

public static List<U> FindDuplicates<T, U>(this List<T> list, Func<T, U> keySelector) 
    { 
     return list.GroupBy(keySelector) 
      .Where(group => group.Count() > 1) 
      .Select(group => group.Key).ToList(); 
    } 

EDIT:

24

あなたはLINQを使用している場合は、次のクエリを使用することができます:

あなたがそれを好む場合
var duplicateItems = from x in list 
        group x by x into grouped 
        where grouped.Count() > 1 
        select grouped.Key; 

か、何が価値があるのは、ここに私の方法であるために

var item2ItemCount = list.GroupBy(item => item).ToDictionary(x=>x.Key,x=>x.Count()); 
+0

+1のHashSet。私は内部的に(注文のために)より速い検索を実行すると思います。 –

+0

PMSL @ '構文上の砂糖なし'。これは本当にLINQ Method構文の別の名前です。 –

1
lblrepeated.Text = ""; 
    string value = txtInput.Text; 
    char[] arr = value.ToCharArray(); 
    char[] crr=new char[1];   
    int count1 = 0;   
    for (int i = 0; i < arr.Length; i++) 
    { 
     int count = 0; 
     char letter=arr[i]; 
     for (int j = 0; j < arr.Length; j++) 
     { 
      char letter3 = arr[j]; 
       if (letter == letter3) 
       { 
        count++; 
       }      
     } 
     if (count1 < count) 
     { 
      Array.Resize<char>(ref crr,0); 
      int count2 = 0; 
      for(int l = 0;l < crr.Length;l++) 
      { 
       if (crr[l] == letter) 
        count2++;      
      } 


      if (count2 == 0) 
      { 
       Array.Resize<char>(ref crr, crr.Length + 1); 
       crr[crr.Length-1] = letter; 
      } 

      count1 = count;    
     } 
     else if (count1 == count) 
     { 
      int count2 = 0; 
      for (int l = 0; l < crr.Length; l++) 
      { 
       if (crr[l] == letter) 
        count2++; 
      } 


      if (count2 == 0) 
      { 
       Array.Resize<char>(ref crr, crr.Length + 1); 
       crr[crr.Length - 1] = letter; 
      } 

      count1 = count; 
     } 
    } 

    for (int k = 0; k < crr.Length; k++) 
     lblrepeated.Text = lblrepeated.Text + crr[k] + count1.ToString(); 
+5

スパゲッティも一緒に食べられますか? – Th3B0Y

6

ことは、あなたは、より汎用的な方法を探しているならここでは例です:

public class Person { 
    public string Name {get;set;} 
    public int Age {get;set;} 
} 

List<Person> list = new List<Person>() { new Person() { Name = "John", Age = 22 }, new Person() { Name = "John", Age = 30 }, new Person() { Name = "Jack", Age = 30 } }; 

var duplicateNames = list.FindDuplicates(p => p.Name); 
var duplicateAges = list.FindDuplicates(p => p.Age); 

foreach(var dupName in duplicateNames) { 
    Console.WriteLine(dupName); // Will print out John 
} 

foreach(var dupAge in duplicateAges) { 
    Console.WriteLine(dupAge); // Will print out 30 
} 
関連する問題