web-dev-qa-db-fra.com

Des moyens rapides pour éviter les doublons dans une liste <> en C #

Mon programme C # génère des chaînes aléatoires à partir d'un modèle donné. Ces chaînes sont stockées dans une liste. Comme aucun doublon n'est autorisé, je le fais comme ceci:

List<string> myList = new List<string>();
for (int i = 0; i < total; i++) {
  string random_string = GetRandomString(pattern);
  if (!myList.Contains(random_string)) myList.Add(random_string);
}

Comme vous pouvez l'imaginer, cela fonctionne bien pour plusieurs centaines d'entrées. Mais je suis confronté à la situation pour générer plusieurs millions de chaînes. Et avec chaque chaîne ajoutée, la recherche de doublons devient de plus en plus lente.

Existe-t-il des moyens plus rapides d'éviter les doublons?

28
Robert Strauch

Utilisez une structure de données qui peut déterminer plus efficacement si un élément existe, à savoir un HashSet. Il peut déterminer si un élément est dans l'ensemble en temps constant, quel que soit le nombre d'éléments dans l'ensemble.

Si vous vraiment avez besoin des éléments dans un List à la place, ou si vous avez besoin que les éléments de la liste résultante soient dans l'ordre où ils ont été générés, alors vous pouvez stocker les données dans un liste et un hachage; ajouter l'élément aux deux collections s'il n'existe pas actuellement dans le HashSet.

44
Servy

N'utilisez pas List<>. Utilisation Dictionary<> ou HashSet<> au lieu!

9
catfood

La façon la plus simple est d'utiliser ceci:

myList = myList.Distinct().ToList();

Bien que cela nécessite de créer la liste une fois, puis de créer une nouvelle liste. Une meilleure façon pourrait être de faire votre générateur à l'avance:

public IEnumerable<string> GetRandomStrings(int total, string pattern)
{
    for (int i = 0; i < total; i++) 
    {
        yield return GetRandomString(pattern);
    }
}

...

myList = GetRandomStrings(total, pattern).Distinct().ToList();

Bien sûr, si vous n'avez pas besoin d'accéder aux éléments par index, vous pouvez probablement améliorer encore plus l'efficacité en supprimant le ToList et en utilisant simplement un IEnumerable.

8
p.s.w.g

Vous pouvez utiliser un HashSet<string> si la commande n'est pas importante:

HashSet<string> myHashSet = new HashSet<string>();
for (int i = 0; i < total; i++) 
{
   string random_string = GetRandomString(pattern);
   myHashSet.Add(random_string);
}

La classe HashSet fournit des opérations d'ensemble hautes performances. Un ensemble est une collection qui ne contient aucun élément en double et dont les éléments ne sont pas dans un ordre particulier.

MSDN

Ou si l'ordre est important, je recommanderais d'utiliser un SortedSet (.net 4.5 uniquement)

6
DGibbs

pas un bon moyen mais une sorte de solution rapide, prenez un bool pour vérifier si dans la liste entière il y a une entrée en double.

bool containsKey;
string newKey;

    public void addKey(string newKey){

         foreach(string key in MyKeys){
           if(key == newKey){
             containsKey = true;
          }
         }

      if(!containsKey){
       MyKeys.add(newKey);
     }else{
       containsKey = false;
     }

    }
1
Amir Javed

Une table de hachage serait un moyen plus rapide de vérifier si un élément existe qu'une liste.

0
Zdravko Danev

As-tu essayé:

myList = myList.Distinct()
0
jdehlin