2013-06-24 27 views
17

Muszę znaleźć i usunąć duplikaty z listy krotek. Zasadniczo moja konstrukcja jest wykonana tak:Znajdowanie i usuwanie duplikatów na liście krotek w języku C#

List<Tuple<string, string>> myList = new List<Tuple<string, string>>(); 

**** 

private void FillStructure() 
{ 
    myList.Add(Tuple.Create<string, string>("A", "B")); 
    myList.Add(Tuple.Create<string, string>("A", "C")); 
    myList.Add(Tuple.Create<string, string>("C", "B")); 
    myList.Add(Tuple.Create<string, string>("C", "B")); // Duplicate 
    myList.Add(Tuple.Create<string, string>("A", "D")); 

    FindAndRemoveDuplicates(myList); 
} 

private void FindAndRemoveDuplicates(List<Tuple<string, string>> myList) 
{ 
     // how can I perform this ? 
} 

nie mogę używać słownika, bo mogę mieć te same kluczowe ale różne wartości! góry dziękuję

Odpowiedz

19

Można użyć Distinct() sposób LINQ coś takiego:

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

pamiętać, że ten będzie ponownie utworzyć listę, zamiast usuwania duplikatów w miejscu.

+0

Rozwiązaniem było tak proste! Dziękuję Ci! :) – davideberdin

0

Zastosowanie distinct() metoda:

myList.Distinct().ToList(); 
0

Jeśli chcesz rozwiązanie, które zmienia wykaz w miejscu, można skorzystać z HashSet<T> (lub dla starszych Ramki do Dictionary<Tuple<string, string>, object> i ignorować wartości):

var existing = new HashSet<Tuple<string, string>>(); 

for (int i = myList.Count - 1; i >= 0; i--) 
{ 
    if (existing.Contains(myList[i])) 
    { 
     myList.RemoveAt(i); 
    } 
    else 
    { 
     existing.Add(myList[i]); 
    } 
} 

Odliczamy wstecz bez użycia iteratora (w przeciwnym razie pojawią się błędy zmieniające listę podczas iteracji).

HashSet<T> ma również przeciążenia, aby nadpisywać równość, jeśli jej potrzebujesz.

Osobiście wybrałbym dasblinkenlight's answer dla czytelności.

6

Można użyć HashSet dla tych celów (http://msdn.microsoft.com/en-us/library/bb359438.aspx)

class SameTuplesComparer<T1, T2> : EqualityComparer<Tuple<T1, T2>> 
{ 
    public override bool Equals(Tuple<T1, T2> t1, Tuple<T1, T2> t2) 
    { 
     return t1.Item1.Equals(t2.Item1) && t1.Item2.Equals(t2.Item2) 
    } 


    public override int GetHashCode(Tuple<T1, T2> t) 
    { 
    return base.GetHashCode(); 
    } 
} 

Więc jeśli napisać własny porównywarka można porównać strun trochę inaczej (jako przykład, nie casesensetive):

class SameStringTuplesComparer: EqualityComparer<Tuple<string, string>> 
{ 
    public override bool Equals(Tuple<string, string> t1, Tuple<string, string> t2) 
    { 
     return t1.Item1.Equals(t2.Item1, StringComparison.CurrentCultureIgnoreCase) && t1.Item2.Equals(t2.Item2, StringComparison.CurrentCultureIgnoreCase) 
    } 


    public override int GetHashCode(Tuple<string, string> t) 
    { 
    return base.GetHashCode(); 
    } 
} 

Następnie w kodzie:

var hashSet = new HashSet<Tuple<string, string>>(list, new SameTuplesComparer()); 

Albo bez własnego porównać r:

var hashSet = HashSet<Tuple<string, string>>(list); 

Teraz możesz dodawać elementy do hashSet, a wszystkie elementy będą unikalne. Po wykonane z elementów dodających można przekonwertować go ponownie listę:

var uniquedList = hashSet.ToList(); 

Albo po prostu użyć list.Distinct().ToList()

+0

Zauważ, że kończysz na 'HashSet ' w tym przypadku, a nie 'List '. Również 'Tuple ' nie będzie wymagało dostarczenia porównania. –

+0

Odpowiedź została zredagowana, dzięki –

+0

+1 Dla dodatkowej alternatywy. –