74 votes

C# Déterminer les doublons dans une liste

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

1 votes

Je me souviens avoir vu cette question ici avant et les gens ont suggéré un truc bien, je ne me souviens plus ce que c'était mais... attendez... jon skeet est dans le coin

1 votes

Votre question semble avoir reçu une réponse, vous devriez la marquer en conséquence, si vous n'êtes pas satisfait, vous pouvez modifier votre question pour l'expliquer plus clairement ;)

169voto

Justin Niessner Points 144953

À moins que je ne manque quelque chose, vous devriez pouvoir vous en sortir avec quelque chose de simple, en utilisant les éléments suivants Distinct() . Certes, ce ne sera pas la mise en œuvre la plus complexe que vous puissiez imaginer, mais elle vous indiquera si des doublons ont été supprimés :

var list = new List<string>();

// Fill the list

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

6 votes

+ 1 si je me souviens bien Distinct() utilise un Hashtable en interne, donc devrait être O(n)

0 votes

Je me demande à quel point distinct est rapide... s'il ne fait pas la "boucle imbriquée n-carré" comme Kenny a mentionné qu'il aimerait l'éviter.

2 votes

N'appelez pas la méthode list.Count(). Utilisez plutôt la propriété Count. Je sais que LINQ est optimisé et qu'il l'utilisera en interne mais je pense quand même qu'il est préférable d'utiliser la propriété.

61voto

Ali Points 640

Ce problème a été abordé ici : Duplicata de MSDN linq Le lien contient un exemple complet que vous pouvez suivre.

4 votes

Cela fonctionnera certainement, mais prendra plus de temps que nécessaire (le PO a seulement besoin de savoir si les doublons existent ou non... pas quelles sont les valeurs des doublons).

10 votes

Ceci est plus utile si vous avez besoin de connaître les valeurs dupliquées.

1 votes

Premier résultat de Google pour mon problème. C'est vraiment une bonne information à avoir ici.

22voto

KyleMit Points 6937

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

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

Voici une méthode d'extension LINQ à la fois en C# et en 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

Note : pour vérifier s'il y a pas de les doublons, il suffit de changer Any à All

2 votes

C'est agréable et élégant, et c'est similaire à l'approche décrit ici qui renvoie également des doublons.

14voto

Trinidad Points 1733

Placez tous les éléments dans un ensemble et si le compte de l'ensemble est différent du compte de la liste, alors 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.

5 votes

N'appelez pas la méthode list.Count(). Utilisez plutôt la propriété Count. Je sais que LINQ est optimisé et qu'il l'utilisera en interne mais je pense quand même qu'il est préférable d'utiliser la propriété.

3 votes

Je reconnais qu'il sera plus efficace s'il y a des doublons . Mais s'il n'y a pas de doublons, alors il fait la même quantité de travail. Le choix de la méthode à utiliser dépend probablement du fait que le cas "normal" est qu'il n'y ait pas de doublons.

1 votes

@Petar Petrov : Bon point. Il faudrait probablement utiliser foreach . Et faites le paramètre IEnumerable<T> plutôt que List<T> .

3voto

Ian P Points 7930

Quelque chose de ce genre est relativement simple et vous fournira un compte des 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 ressemble à l'implémentation de Distinct, mais je n'en suis pas certain.

2 votes

HashSet semble plus simple à utiliser.

1 votes

Oui, c'est plus logique.

0 votes

@Trinidad : mais ne vous donnera pas un compte

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X