Eliminar duplicados de una lista en C#


¿Alguien tiene un método rápido para des-duplicar una Lista genérica en C#?

 412
Author: JC Grubbs, 2008-09-06

23 answers

Quizás deberías considerar usar un HashSet .

Desde el enlace MSDN:

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
Author: Jason Baker,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-01-06 13:52:13

Si está usando.Net 3+, puede usar Linq.

List<T> withDupes = LoadSomeData();
List<T> noDupes = withDupes.Distinct().ToList();
 701
Author: Factor Mystic,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-01-29 18:14:32

Qué tal: -

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

En .net 3.5?

 130
Author: ljs,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-06 19:56:06

Simplemente inicialice un HashSet con una Lista del mismo tipo:

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

O, si desea que se devuelva una Lista:

var noDupsList = new HashSet<T>(withDupes).ToList();
 84
Author: Even Mien,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-02-12 19:22:23

Ordénelo, luego marque dos y dos uno al lado del otro, ya que los duplicados se agruparán.

Algo como esto:

list.Sort();
Int32 index = 0;
while (index < list.Count - 1)
{
    if (list[index] == list[index + 1])
        list.RemoveAt(index);
    else
        index++;
}
 45
Author: Lasse Vågsæther Karlsen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-06 19:20:36

Funcionó para mí. simplemente use

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

Reemplace "Type" con el tipo deseado, por ejemplo, int.

 31
Author: Hossein Sarshar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-11-16 14:18:11

Me gusta usar este comando:

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

Tengo estos campos en mi lista: Id, StoreName, City, PostalCode Quería mostrar la lista de ciudades en un menú desplegable que tiene valores duplicados. solución: Agrupe por ciudad y luego elija la primera para la lista.

Espero que ayude :)

 22
Author: Eric,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-07-27 18:57:16

Como kronoz dijo en.Net 3.5 puede usar Distinct().

En. Net 2 puedes imitarlo:

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

Esto se puede usar para desduplicar cualquier colección y devolverá los valores en el orden original.

Normalmente es mucho más rápido filtrar una colección (como lo hacen Distinct() y esta muestra) que eliminar elementos de ella.

 22
Author: Keith,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-06-09 17:24:56

Un método de extensión podría ser una forma decente de hacerlo... algo como esto:

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

Y luego llamar así, por ejemplo:

List<int> myFilteredList = unfilteredList.Deduplicate();
 12
Author: Geoff Taylor,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-06-02 08:48:19

En Java (asumo que C# es más o menos idéntico):

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

Si realmente querías mutar la lista original:

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

Para preservar el orden, simplemente reemplace el HashSet con LinkedHashSet.

 10
Author: Tom Hawtin - tackline,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-08 15:39:09

Si no te importa el orden, puedes meter los elementos en un HashSet, si quieres mantener el orden, puedes hacer algo como esto:

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

O el camino Linq:

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

Editar: El método HashSet es O(N) el tiempo y O(N) el espacio mientras se ordena y luego se hace único (como lo sugieren @lassevk y otros) es O(N*lgN) el tiempo y O(1) el espacio, por lo que no está tan claro para mí (como lo estaba a primera vista) que disculpas por el voto negativo temporal...)

 5
Author: Motti,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 10:31:10

Como método auxiliar (sin Linq):

public static List<T> Distinct<T>(this List<T> list)
{
    return (new HashSet<T>(list)).ToList();
}
 5
Author: Grant,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-11-18 21:45:29

Utilice el método de Linq Union.

Nota: Esta solución no requiere conocimiento de Linq, aparte de que existe.

Código

Comience agregando lo siguiente a la parte superior de su archivo de clase:

using System.Linq;

Ahora, puede usar lo siguiente para eliminar duplicados de un objeto llamado, obj1:

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

Nota: Cambie el nombre de obj1 al nombre de su objeto.

Cómo obras

  1. El comando Union enumera una de cada entrada de dos objetos fuente. Puesto que obj1 es ambos objetos fuente, esto reduce obj1 a una de cada entrada.

  2. El ToList()) devuelve una nueva Lista. Esto es necesario, porque comandos Linq como Union devuelve el resultado como un resultadoumumerable en lugar de modificar la Lista original o devolver una nueva Lista.

 5
Author: Knickerless-Noggins,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-02-13 12:56:58

Aquí hay un método de extensión para eliminar duplicados adyacentes in-situ. Llama primero a Sort () y pasa el mismo IComparer. Esto debería ser más eficiente que la versión de Lasse V. Karlsen que llama a RemoveAt repetidamente (lo que resulta en múltiples movimientos de memoria de bloque).

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
Author: gary,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-03-05 16:33:52

Podría ser más fácil simplemente asegurarse de que los duplicados no se agreguen a la lista.

if(items.IndexOf(new_item) < 0) 
    items.add(new_item)
 3
Author: Chris,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-10-19 21:00:27

Puede usar Union

obj2 = obj1.Union(obj1).ToList();
 2
Author: flagamba,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-02-12 16:54:14

Otra forma en. 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
Author: Bhasin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-02-10 06:55:52

Hay muchas maneras de resolver-el problema de duplicados en la Lista, a continuación es una de ellas:

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

Saludos Ravi Ganesan

 1
Author: Ravi Ganesan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-04-10 05:02:59

Aquí hay una solución simple que no requiere ningún LINQ difícil de leer ni ninguna ordenación previa de la lista.

   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
Author: David J.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-02-14 12:20:12

La respuesta de David J. es un buen método, sin necesidad de objetos adicionales, clasificación, etc. Sin embargo, se puede mejorar:

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

Así que el bucle exterior va arriba abajo para toda la lista, pero el bucle interior va abajo "hasta que se alcanza la posición del bucle exterior".

El bucle externo se asegura de que se procese toda la lista, el bucle interno encuentra los duplicados reales, esos solo pueden ocurrir en la parte que el bucle externo no ha procesado todavía.

O si no quieres hacer de abajo hacia arriba para el bucle interno, puede hacer que el bucle interno comience en outerIndex + 1.

 1
Author: Guest,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
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
Author: Paul Richards,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-05-14 11:11:48

Al instalar el paquete MoreLINQ a través de Nuget, puede distinguir fácilmente la lista de objetos por una propiedad

IEnumerable<Catalogue> distinctCatalogues = catalogues.DistinctBy(c => c.CatalogueCode); 
 1
Author: dush88c,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-03-23 14:16:21

Una implementación sencilla e intuitiva:

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
Author: Moctar Haiz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-04-19 09:26:54