Duplicaten verwijderen uit een lijst<T> in C#

Heeft iemand een snelle methode om een generieke lijst in C# te dedupliceren?


Antwoord 1, autoriteit 100%

Misschien kunt u overwegen een HashSette gebruiken.

Vanaf de MSDN-link:

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 }
 */

Antwoord 2, autoriteit 96%

Als je .Net 3+ gebruikt, kun je Linq gebruiken.

List<T> withDupes = LoadSomeData();
List<T> noDupes = withDupes.Distinct().ToList();

Antwoord 3, autoriteit 92%

Wat dacht je van:

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

In .net 3.5?


Antwoord 4, autoriteit 39%

Initialiseer eenvoudig een HashSet met een lijst van hetzelfde type:

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

Of, als u een lijst wilt retourneren:

var noDupsList = new HashSet<T>(withDupes).ToList();

Antwoord 5, autoriteit 20%

Sorteer het en vink vervolgens twee en twee naast elkaar aan, omdat de duplicaten aan elkaar zullen klonteren.

Zoiets:

list.Sort();
Int32 index = list.Count - 1;
while (index > 0)
{
    if (list[index] == list[index - 1])
    {
        if (index < list.Count - 1)
            (list[index], list[list.Count - 1]) = (list[list.Count - 1], list[index]);
        list.RemoveAt(list.Count - 1);
        index--;
    }
    else
        index--;
}

Opmerkingen:

  • De vergelijking wordt van achteren naar voren gedaan, om te voorkomen dat u na elke verwijdering een lijst met resorts hoeft te gebruiken
  • Dit voorbeeld gebruikt nu C# Value Tuples om de swaps uit te voeren, vervang deze door de juiste code als je die niet kunt gebruiken
  • Het eindresultaat is niet meer gesorteerd

Antwoord 6, autoriteit 16%

Ik gebruik deze opdracht graag:

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

Ik heb deze velden in mijn lijst: Id, StoreName, City, PostalCode
Ik wilde een lijst met steden weergeven in een vervolgkeuzelijst met dubbele waarden.
oplossing: Groepeer op stad en kies dan de eerste voor de lijst.

Ik hoop dat het helpt 🙂


Antwoord 7, autoriteit 13%

Het werkte voor mij. gebruik gewoon

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

Vervang “Type” door het gewenste type, b.v. int.


Antwoord 8, autoriteit 10%

Zoals kronoz zei in .Net 3.5 kun je Distinct()gebruiken.

In .Net 2 zou je het kunnen nabootsen:

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

Dit kan worden gebruikt om elke verzameling te ontdubbelen en de waarden in de oorspronkelijke volgorde terug te geven.

Het is normaal gesproken veel sneller om een collectie te filteren (zoals zowel Distinct()als dit voorbeeld doen) dan items eruit te verwijderen.


Antwoord 9, autoriteit 6%

Een uitbreidingsmethode kan een goede manier zijn om te gaan… zoiets als dit:

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

En bel dan zo, bijvoorbeeld:

List<int> myFilteredList = unfilteredList.Deduplicate();

Antwoord 10, autoriteit 5%

In Java (ik neem aan dat C# min of meer identiek is):

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

Als je de originele lijst echt wilt muteren:

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

Om de orde te behouden, vervang je HashSet door LinkedHashSet.


Antwoord 11, autoriteit 5%

Hiermee worden verschillende (de elementen zonder dubbele elementen) gebruikt en opnieuw in een lijst omgezet:

List<type> myNoneDuplicateValue = listValueWithDuplicate.Distinct().ToList();

Antwoord 12, autoriteit 4%

Gebruik de Union-methode van Linq.

Opmerking: deze oplossing vereist geen kennis van Linq, behalve dat het bestaat.

Code

Begin door het volgende toe te voegen aan de bovenkant van je klasbestand:

using System.Linq;

U kunt nu het volgende gebruiken om duplicaten te verwijderen van een object met de naam obj1:

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

OPMERKING: Hernoemen obj1naar de naam van uw object.

Hoe het werkt

  1. De opdracht van de Unie somt een van elke invoer van twee bronobjecten op. Aangezien OBJ1 beide bronobjecten is, vermindert dit OBJ1 tot een van elke invoer.

  2. De ToList()retourneert een nieuwe lijst. Dit is noodzakelijk, omdat LINQ-opdrachten zoals Unionhet resultaat retourneert als een IEenerable resultaat in plaats van de originele lijst aan te passen of een nieuwe lijst te retourneren.


13, Autoriteit 3%

Als helpermethode (zonder LINQ):

public static List<T> Distinct<T>(this List<T> list)
{
    return (new HashSet<T>(list)).ToList();
}

14, Autoriteit 3%

Installeren van de Morelinq pakket via Nuget, kunt u eenvoudig een objectlijstje maken met een eigendom

IEnumerable<Catalogue> distinctCatalogues = catalogues.DistinctBy(c => c.CatalogueCode); 

15, Autoriteit 3%

Als u niet om de bestelling geeft, kunt u gewoon de items in een HashSetschoven, als u DOEN Wilt u de bestelling onderhouden die u zo kunt behouden :

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

of de LINQ-manier:

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

EDIT: De HashSetMETHODE IS O(N)TIJD EN O(N)RUIMTE TIJDENS SORTEREN en dan uniek (zoals gesuggereerd door @ lassevk en anderen ) is O(N*lgN)tijd en O(1)ruimte, dus het is niet zo duidelijk voor mij (zoals het op het eerste gezicht was) dat de sorteermanier inferieur is (Mijn excuses voor de tijdelijke down-stemming …)


16, Autoriteit 3%

Hier is een uitbreidingsmethode voor het verwijderen van aangrenzende duplicaten in situ. Oproep Sorteer () eerst en passeer dezelfde IComparer. Dit moet efficiënter zijn dan de versie van Lasse V. Karlsen die herhaaldelijk removeat (resulteert in multiple block-geheugenbewegingen).

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

17, Autoriteit 2%

is mogelijk gemakkelijker om te zorgen dat duplicaten niet aan de lijst worden toegevoegd.

if(items.IndexOf(new_item) < 0) 
    items.add(new_item)

18

U kunt de Unie

gebruiken

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

19

een andere manier in .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();
    }

20

Er zijn veel manieren om op te lossen – het probleem van de duplicaten in de lijst, hieronder is een van hen:

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

Proost
Ravi Ganesan


Antwoord 21

Hier is een eenvoudige oplossing waarvoor geen moeilijk leesbare LINQ of voorafgaande sortering van de lijst nodig is.

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

Antwoord 22

David J.’s antwoord is een goede methode, geen behoefte aan extra objecten, sorteren, etc. Het kan echter worden verbeterd:

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

Dus de buitenste lus gaat van boven naar beneden voor de hele lijst, maar de binnenste lus gaat naar beneden “totdat de positie van de buitenste lus is bereikt”.

De buitenste lus zorgt ervoor dat de hele lijst wordt verwerkt, de binnenste lus vindt de daadwerkelijke duplicaten, die kunnen alleen gebeuren in het deel dat de buitenste lus nog niet heeft verwerkt.

Of als u de binnenste lus niet van onder naar boven wilt doen, kunt u de binnenste lus laten beginnen bij outerIndex + 1.


Antwoord 23

Een eenvoudige intuïtieve implementatie:

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

Antwoord 24

Alle antwoorden kopiëren lijsten, of maken een nieuwe lijst, of gebruiken langzame functies, of zijn gewoon pijnlijk traag.

Voor zover ik weet is dit de snelste en goedkoopste methodedie ik ken (ook ondersteund door een zeer ervaren programmeur die gespecialiseerd is in realtime natuurkundige optimalisatie).

// Duplicates will be noticed after a sort O(nLogn)
list.Sort();
// Store the current and last items. Current item declaration is not really needed, and probably optimized by the compiler, but in case it's not...
int lastItem = -1;
int currItem = -1;
int size = list.Count;
// Store the index pointing to the last item we want to keep in the list
int last = size - 1;
// Travel the items from last to first O(n)
for (int i = last; i >= 0; --i)
{
    currItem = list[i];
    // If this item was the same as the previous one, we don't want it
    if (currItem == lastItem)
    {
        // Overwrite last in current place. It is a swap but we don't need the last
       list[i] = list[last];
        // Reduce the last index, we don't want that one anymore
        last--;
    }
    // A new item, we store it and continue
    else
        lastItem = currItem;
}
// We now have an unsorted list with the duplicates at the end.
// Remove the last items just once
list.RemoveRange(last + 1, size - last - 1);
// Sort again O(n logn)
list.Sort();

De uiteindelijke kosten zijn:

nlogn + n + nlogn = n + 2nlogn = O(nlogn)wat best aardig is.

Opmerking over RemoveRange:
Aangezien we het aantal van de lijst niet kunnen instellen en het gebruik van de verwijderfuncties niet kunnen gebruiken, weet ik niet precies de snelheid van deze bewerking, maar ik denk dat dit de snelste manier is.


Antwoord 25

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

Antwoord 26

Ik denk dat de eenvoudigste manier is:

Maak een nieuwe lijst en voeg een uniek item toe.

Voorbeeld:

       class MyList{
    int id;
    string date;
    string email;
    }
    List<MyList> ml = new Mylist();
ml.Add(new MyList(){
id = 1;
date = "2020/09/06";
email = "zarezadeh@gmailcom"
});
ml.Add(new MyList(){
id = 2;
date = "2020/09/01";
email = "zarezadeh@gmailcom"
});
 List<MyList> New_ml = new Mylist();
foreach (var item in ml)
                {
                    if (New_ml.Where(w => w.email == item.email).SingleOrDefault() == null)
                    {
                        New_ml.Add(new MyList()
                        {
                          id = item.id,
     date = item.date,
               email = item.email
                        });
                    }
                }

Antwoord 27

Met behulp van HashSetdit kan gemakkelijk worden gedaan.

List<int> listWithDuplicates = new List<int> { 1, 2, 1, 2, 3, 4, 5 };
HashSet<int> hashWithoutDuplicates = new HashSet<int> ( listWithDuplicates );
List<int> listWithoutDuplicates = hashWithoutDuplicates.ToList();

Other episodes