web-dev-qa-db-fra.com

Comment trouver tous les doublons d'une liste <string>?

J'ai un List<string> qui a des mots dupliqués. Je dois trouver tous les mots qui sont des doublons.

Toute astuce pour les obtenir tous?

113
Steven Spielberg

Dans .NET Framework 3.5 et versions ultérieures, vous pouvez utiliser Enumerable.GroupBy qui retourne un énumérable d'énumérables de clés dupliquées, puis filtre tous les énumérables ayant un nombre de <= 1, puis sélectionne leurs clés pour revenir à un seul énumérable:

var duplicateKeys = list.GroupBy(x => x)
                        .Where(group => group.Count() > 1)
                        .Select(group => group.Key);
198
Giuseppe Ottaviano

Si vous utilisez LINQ, vous pouvez utiliser la requête suivante:

var duplicateItems = from x in list
                     group x by x into grouped
                     where grouped.Count() > 1
                     select grouped.Key;

ou, si vous le préférez sans le sucre syntaxique:

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

Cela regroupe tous les éléments identiques, puis les filtre uniquement aux groupes de plusieurs éléments. Enfin, il sélectionne uniquement la clé dans ces groupes, car vous n’avez pas besoin du décompte.

Si vous préférez ne pas utiliser LINQ, vous pouvez utiliser cette méthode d'extension:

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

Cela permet de garder trace des éléments qu’il a vus et cédés. S'il n'a pas encore vu d'élément, il l'ajoute à la liste des éléments visibles, sinon il l'ignore. S'il n'a pas déjà cédé un élément, il le cède, sinon il l'ignore.

30
ICR

et sans le 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);
19
evilone

Si vous recherchez une méthode plus générique:

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: Voici un exemple:

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
}
8
Mauricio Ramalho

Utiliser LINQ, bien sûr. Le code ci-dessous vous donnerait un dictionnaire d’élément item en tant que chaîne, ainsi que le nombre de chaque élément de votre liste de sources.

var item2ItemCount = list.GroupBy(item => item).ToDictionary(x=>x.Key,x=>x.Count());
5
Manish Basantani

Pour ce que ça vaut, voici mon chemin:

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])));
3
Shadow Wizard

Je suppose que chaque chaîne de votre liste contient plusieurs mots, laissez-moi savoir si c'est inexact.

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()
                     }
3
Thomas Levesque

J'utilise une méthode comme celle pour vérifier les entrées en double dans une chaîne:

public static IEnumerable<string> CheckForDuplicated(IEnumerable<string> listString)
{
    List<string> duplicateKeys = new List<string>();
    List<string> notDuplicateKeys = new List<string>();
    foreach (var text in listString)
    {
        if (notDuplicateKeys.Contains(text))
        {
            duplicateKeys.Add(text);
        }
        else
        {
            notDuplicateKeys.Add(text);
        }
    }
    return duplicateKeys;
}

Ce n’est peut-être pas le moyen le plus court ou le plus élégant, mais je pense que cela est très lisible.

1
George Wurthmann
    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();
1
kittu