Supprimer les doublons d'une liste en C#

Quelqu'un a une méthode rapide pour dé-dupliquer une liste générique dans C#?

412
demandé sur JC Grubbs 2008-09-06 23:15:27

23 réponses

peut-être devriez-vous envisager d'utiliser un HashSet .

De la MSDN lien:

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        HashSet<int> evenNumbers = new HashSet<int>();
        HashSet<int> oddNumbers = new HashSet<int>();

        for (int i = 0; i < 5; i++)
        {
            // Populate numbers with just even numbers.
            evenNumbers.Add(i * 2);

            // Populate oddNumbers with just odd numbers.
            oddNumbers.Add((i * 2) + 1);
        }

        Console.Write("evenNumbers contains {0} elements: ", evenNumbers.Count);
        DisplaySet(evenNumbers);

        Console.Write("oddNumbers contains {0} elements: ", oddNumbers.Count);
        DisplaySet(oddNumbers);

        // Create a new HashSet populated with even numbers.
        HashSet<int> numbers = new HashSet<int>(evenNumbers);
        Console.WriteLine("numbers UnionWith oddNumbers...");
        numbers.UnionWith(oddNumbers);

        Console.Write("numbers contains {0} elements: ", numbers.Count);
        DisplaySet(numbers);
    }

    private static void DisplaySet(HashSet<int> set)
    {
        Console.Write("{");
        foreach (int i in set)
        {
            Console.Write(" {0}", i);
        }
        Console.WriteLine(" }");
    }
}

/* This example produces output similar to the following:
 * evenNumbers contains 5 elements: { 0 2 4 6 8 }
 * oddNumbers contains 5 elements: { 1 3 5 7 9 }
 * numbers UnionWith oddNumbers...
 * numbers contains 10 elements: { 0 2 4 6 8 1 3 5 7 9 }
 */
202
répondu Jason Baker 2017-01-06 13:52:13

si vous utilisez .Net 3+, Vous pouvez utiliser Linq.

List<T> withDupes = LoadSomeData();
List<T> noDupes = withDupes.Distinct().ToList();
701
répondu Factor Mystic 2009-01-29 18:14:32

que dire de: -

var noDupes = list.Distinct().ToList();

dans .net 3.5?

130
répondu ljs 2008-09-06 19:56:06

il suffit D'initialiser un HashSet avec une liste du même type:

var noDupes = new HashSet<T>(withDupes);

ou, si vous voulez une liste retournée:

var noDupsList = new HashSet<T>(withDupes).ToList();
84
répondu Even Mien 2017-02-12 19:22:23

Triez-le, puis cochez deux et deux à côté de l'autre, car les doublons vont s'agglutiner.

quelque chose comme ça:

list.Sort();
Int32 index = 0;
while (index < list.Count - 1)
{
    if (list[index] == list[index + 1])
        list.RemoveAt(index);
    else
        index++;
}
45
répondu Lasse Vågsæther Karlsen 2008-09-06 19:20:36

ça a marché pour moi. il suffit d'utiliser

List<Type> liIDs = liIDs.Distinct().ToList<Type>();

remplacer" Type " par le type désiré, par exemple int.

31
répondu Hossein Sarshar 2012-11-16 14:18:11

j'aime utiliser cette commande:

List<Store> myStoreList = Service.GetStoreListbyProvince(provinceId)
                                                 .GroupBy(s => s.City)
                                                 .Select(grp => grp.FirstOrDefault())
                                                 .OrderBy(s => s.City)
                                                 .ToList();

j'ai ces champs dans ma liste: Id, StoreName, City, PostalCode Je voulais montrer la liste des villes dans une liste déroulante qui a des valeurs dupliquées. solution: Groupe par ville puis choisissez le premier de la liste.

j'espère que cela aide :)

22
répondu Eric 2012-07-27 18:57:16

comme kronoz l'a dit dans .Net 3.5, vous pouvez utiliser Distinct() .

dans .Net 2 Vous pouvez l'imiter:

public IEnumerable<T> DedupCollection<T> (IEnumerable<T> input) 
{
    var passedValues = new HashSet<T>();

    // Relatively simple dupe check alg used as example
    foreach(T item in input)
        if(passedValues.Add(item)) // True if item is new
            yield return item;
}

cela peut être utilisé pour dépouiller n'importe quelle collection et retourner les valeurs dans l'ordre original.

normalement, il est beaucoup plus rapide de filtrer une collection (comme Distinct() et cet échantillon le fait) qu'il ne le serait pour en retirer des articles.

22
répondu Keith 2015-06-09 17:24:56

une méthode d'extension pourrait être une bonne façon de faire... quelque chose comme ceci:

public static List<T> Deduplicate<T>(this List<T> listToDeduplicate)
{
    return listToDeduplicate.Distinct().ToList();
}

et puis appelez comme ceci, par exemple:

List<int> myFilteredList = unfilteredList.Deduplicate();
12
répondu Geoff Taylor 2011-06-02 08:48:19

en Java (je suppose que C# est plus ou moins identique):

list = new ArrayList<T>(new HashSet<T>(list))

si vous avez vraiment voulu muter la liste originale:

List<T> noDupes = new ArrayList<T>(new HashSet<T>(list));
list.clear();
list.addAll(noDupes);

pour préserver l'ordre, il suffit de remplacer le HashSet par LinkedHashSet.

10
répondu Tom Hawtin - tackline 2008-09-08 15:39:09

si vous ne vous souciez pas de la commande, vous pouvez simplement mettre les articles dans un HashSet , si vous do si vous voulez maintenir la commande, vous pouvez faire quelque chose comme ceci:

var unique = new List<T>();
var hs = new HashSet<T>();
foreach (T t in list)
    if (hs.Add(t))
        unique.Add(t);

Ou Linq:

var hs = new HashSet<T>();
list.All( x =>  hs.Add(x) );

Edit: la méthode HashSet est O(N) time et O(N) space tout en triant et en faisant unique (comme suggéré par @ lassevk et autres) est O(N*lgN) temps et O(1) espace de sorte qu'il n'est pas si clair pour moi (comme il l'était à première vue) que la voie de tri est inférieure (mes excuses pour le vote temporaire vers le bas...)

5
répondu Motti 2017-05-23 10:31:10

comme méthode d'aide (sans Linq):

public static List<T> Distinct<T>(this List<T> list)
{
    return (new HashSet<T>(list)).ToList();
}
5
répondu Grant 2014-11-18 21:45:29

utiliser la méthode de Linq Union .

Note: Cette solution n'exige aucune connaissance de Linq, sauf qu'elle existe.

Code

commencez par ajouter ce qui suit Au début de votre fichier de classe:

using System.Linq;

Maintenant, vous pouvez utiliser ce qui suit pour supprimer les doublons d'un objet appelé, obj1 :

obj1 = obj1.Union(obj1).ToList();

Note: renommez obj1 au nom de votre objet.

Comment ça marche

  1. la commande Union Liste une entrée de chaque objet source. Comme obj1 est à la fois un objet source, cela réduit obj1 à une entrée par entrée.

  2. le ToList() retourne une nouvelle liste. Cela est nécessaire, parce que les commandes de Linq comme Union retourne le résultat comme un résultat IEnumerable au lieu de modifier la liste originale ou de retourner une nouvelle liste.

5
répondu Knickerless-Noggins 2018-02-13 12:56:58

Voici une méthode d'extension pour enlever les doublons adjacents in-situ. Appeler D'abord Sort() et passer dans le même IComparer. Cela devrait être plus efficace que la version de Lasse V. Karlsen qui appelle RemoveAt à plusieurs reprises (résultant en plusieurs blocks de déplacement de mémoire).

public static void RemoveAdjacentDuplicates<T>(this List<T> List, IComparer<T> Comparer)
{
    int NumUnique = 0;
    for (int i = 0; i < List.Count; i++)
        if ((i == 0) || (Comparer.Compare(List[NumUnique - 1], List[i]) != 0))
            List[NumUnique++] = List[i];
    List.RemoveRange(NumUnique, List.Count - NumUnique);
}
4
répondu gary 2014-03-05 16:33:52

pourrait être plus facile de simplement s'assurer que les doublons ne sont pas ajoutés à la liste.

if(items.IndexOf(new_item) < 0) 
    items.add(new_item)
3
répondu Chris 2012-10-19 21:00:27

vous pouvez utiliser Union

obj2 = obj1.Union(obj1).ToList();
2
répondu flagamba 2018-02-12 16:54:14

d'une Autre manière .Net 2.0

    static void Main(string[] args)
    {
        List<string> alpha = new List<string>();

        for(char a = 'a'; a <= 'd'; a++)
        {
            alpha.Add(a.ToString());
            alpha.Add(a.ToString());
        }

        Console.WriteLine("Data :");
        alpha.ForEach(delegate(string t) { Console.WriteLine(t); });

        alpha.ForEach(delegate (string v)
                          {
                              if (alpha.FindAll(delegate(string t) { return t == v; }).Count > 1)
                                  alpha.Remove(v);
                          });

        Console.WriteLine("Unique Result :");
        alpha.ForEach(delegate(string t) { Console.WriteLine(t);});
        Console.ReadKey();
    }
1
répondu Bhasin 2011-02-10 06:55:52

il y a plusieurs façons de résoudre - la question des doublons dans la liste, ci-dessous est l'une d'entre elles:

List<Container> containerList = LoadContainer();//Assume it has duplicates
List<Container> filteredList = new  List<Container>();
foreach (var container in containerList)
{ 
  Container duplicateContainer = containerList.Find(delegate(Container checkContainer)
  { return (checkContainer.UniqueId == container.UniqueId); });
   //Assume 'UniqueId' is the property of the Container class on which u r making a search

    if(!containerList.Contains(duplicateContainer) //Add object when not found in the new class object
      {
        filteredList.Add(container);
       }
  }

santé Ravi Ganesan

1
répondu Ravi Ganesan 2011-04-10 05:02:59

Voici une solution simple qui ne nécessite pas de LINQ difficile à lire ou de tri préalable de la liste.

   private static void CheckForDuplicateItems(List<string> items)
    {
        if (items == null ||
            items.Count == 0)
            return;

        for (int outerIndex = 0; outerIndex < items.Count; outerIndex++)
        {
            for (int innerIndex = 0; innerIndex < items.Count; innerIndex++)
            {
                if (innerIndex == outerIndex) continue;
                if (items[outerIndex].Equals(items[innerIndex]))
                {
                    // Duplicate Found
                }
            }
        }
    }
1
répondu David J. 2012-02-14 12:20:12

la réponse de David J. est une bonne méthode, pas besoin d'objets supplémentaires, de tri, etc. Il peut toutefois être amélioré sur:

for (int innerIndex = items.Count - 1; innerIndex > outerIndex ; innerIndex--)

ainsi la boucle extérieure descend en haut pour la liste entière, mais la boucle intérieure descend en bas "jusqu'à ce que la position de la boucle extérieure soit atteinte".

la boucle extérieure s'assure que la liste entière est traitée, la boucle intérieure trouve les doublons réels, ceux-ci ne peuvent se produire que dans la partie que l'extérieur la boucle n'a pas encore été traités.

ou si vous ne voulez pas faire bottom up pour la boucle intérieure, vous pouvez faire démarrer la boucle intérieure à outerIndex + 1.

1
répondu Guest 2013-10-22 11:10:13
  public static void RemoveDuplicates<T>(IList<T> list )
  {
     if (list == null)
     {
        return;
     }
     int i = 1;
     while(i<list.Count)
     {
        int j = 0;
        bool remove = false;
        while (j < i && !remove)
        {
           if (list[i].Equals(list[j]))
           {
              remove = true;
           }
           j++;
        }
        if (remove)
        {
           list.RemoveAt(i);
        }
        else
        {
           i++;
        }
     }  
  }
1
répondu Paul Richards 2014-05-14 11:11:48

installer le paquet MoreLINQ via Nuget, vous pouvez facilement distinguer la liste des objets par une propriété

IEnumerable<Catalogue> distinctCatalogues = catalogues.DistinctBy(c => c.CatalogueCode); 
1
répondu dush88c 2018-03-23 14:16:21

une simple implémentation intuitive:

public static List<PointF> RemoveDuplicates(List<PointF> listPoints)
{
    List<PointF> result = new List<PointF>();

    for (int i = 0; i < listPoints.Count; i++)
    {
        if (!result.Contains(listPoints[i]))
            result.Add(listPoints[i]);
        }

        return result;
    }
0
répondu Moctar Haiz 2018-04-19 09:26:54