web-dev-qa-db-fra.com

C # Déterminer le doublon dans la liste

Condition: dans une liste non triée, déterminez s'il existe un doublon. La façon typique de procéder est une boucle imbriquée n-carré. Je me demande comment les autres résolvent cela. Existe-t-il une méthode élégante et performante dans Linq? Quelque chose de générique qui prend un lambda ou un comparateur serait bien.

61
kakridge

Sauf si je manque quelque chose, alors vous devriez pouvoir vous en sortir avec quelque chose de simple en utilisant Distinct(). Certes, ce ne sera pas l'implémentation la plus complexe que vous pourriez trouver, mais elle vous dira si des doublons sont supprimés:

var list = new List<string>();

// Fill the list

if(list.Count != list.Distinct().Count())
{
     // Duplicates exist
}
131
Justin Niessner

Selon l'article d'Eric White sur la façon de Trouver des doublons à l'aide de LINQ :

Un moyen simple de rechercher des doublons consiste à écrire une requête qui regroupe par identifiant, puis à filtrer les groupes qui ont plusieurs membres. Dans l'exemple suivant, nous voulons savoir que 4 et 3 sont des doublons:

int[] listOfItems = new[] { 4, 2, 3, 1, 6, 4, 3 };
var duplicates = listOfItems
    .GroupBy(i => i)
    .Where(g => g.Count() > 1)
    .Select(g => g.Key);
foreach (var d in duplicates)
    Console.WriteLine(d); // 4,3
44
Ali

Afin de permettre un court-circuit si le doublon existe au début de la liste, vous pouvez ajouter un HashSet<T> et vérifiez la valeur de retour de son .Add méthode.

En utilisant .Any vous pouvez court-circuiter l'énumération dès que vous en trouvez un doublon.

Voici une méthode d'extension LINQ en C # et VB:

CSharp:

public static bool ContainsDuplicates<T>(this IEnumerable<T> enumerable)
{
    var knownKeys = new HashSet<T>();
    return enumerable.Any(item => !knownKeys.Add(item));
}

Visual Basic:

<Extension>
Public Function ContainsDuplicates(Of T)(ByVal enumerable As IEnumerable(Of T)) As Boolean
    Dim knownKeys As New HashSet(Of T)
    Return enumerable.Any(Function(item) Not knownKeys.Add(item))
End Function

Remarque : pour vérifier s'il y a non doublons, changez simplement Any en All

20
KyleMit

Placez tous les éléments dans un ensemble et si le nombre de l'ensemble est différent du nombre de la liste, il y a un doublon.

bool hasDuplicates<T>(List<T> myList) {
    var hs = new HashSet<T>();

    for (var i = 0; i < myList.Count; ++i) {
        if (!hs.Add(myList[i])) return true;
    }
    return false;
}

Devrait être plus efficace que Distinct car il n'est pas nécessaire de parcourir toute la liste.

13
Trinidad

Vous pouvez utiliser la méthode IEnumerable.GroupBy.

var list = new List<string> {"1", "2","3", "1", "2"};
var hasDuplicates = list.GroupBy(x => x).Any(x => x.Skip(1).Any());
2
johnsonlu

Quelque chose dans ce sens est relativement simple et vous fournira un nombre de doublons.

var something = new List<string>() { "One", "One", "Two", "Three" };

var dictionary = new Dictionary<string, int>();

something.ForEach(s =>
    {
        if (dictionary.ContainsKey(s))
        {
            dictionary[s]++;
        }
        else
        {
            dictionary[s] = 1;
        }
    });

J'imagine que cela est similaire à la mise en œuvre de Distinct, bien que je ne sois pas certain.

2
Ian P

Si vous utilisez des entiers ou des ensembles bien ordonnés, utilisez un arbre binaire pour les performances O (nlog n).

Alternativement, trouvez un autre moyen de tri plus rapide, puis vérifiez simplement que chaque valeur est différente de la précédente.

1
andrewjs

Vous pouvez utiliser la méthode d'extension Distinct () pour IEnumerable

1
Black Jack Pershing

Utilisation Enumerable.Any avec HashSet.Add comme:

List<string> list = new List<string> {"A", "A", "B", "C", "D"};
HashSet<string> hashSet = new HashSet<string>();
if(list.Any(r => !hashSet.Add(r)))
{
   //duplicate exists. 
}

HashSet.Add renverrait false si l'élément existe déjà dans le HashSet. Cela ne répétera pas toute la liste.

1
Habib

Vous pouvez utiliser l'instruction Distinct() pour rechercher des enregistrements uniques. Comparez ensuite avec la liste générique d'origine comme celle-ci:

  if (dgCoil.ItemsSource.Cast<BLL.Coil>().ToList().Count != dgCoil.ItemsSource.Cast<BLL.Coil>().Select(c => c.CoilNo).Distinct().Count())
  {    
    //Duplicate detected !!
    return;
  }
0
Murat ÜRKMEZ