2013-06-24 4 views
17

Devo trovare e rimuovere i duplicati da un elenco di tuple. In sostanza, la mia struttura è composta così:Trova ed elimina i duplicati nell'elenco delle tuple in 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 ? 
} 

non posso utilizzare un dizionario perché posso avere gli stessi valori fondamentali, ma diverse! Grazie in anticipo

risposta

19

È possibile utilizzare Distinct() metodo LINQ, in questo modo:

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

Si noti che questo sarebbe ricreare l'elenco, piuttosto che rimuovere i duplicati in atto.

+0

La soluzione era così semplice! Grazie! :) – davideberdin

0

Uso distinct() metodo:

myList.Distinct().ToList(); 
0

Se si desidera una soluzione che modifica l'elenco sul posto, si può fare uso di un HashSet<T> (o per anziani framework un Dictionary<Tuple<string, string>, object> e ignorare il valore):

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

Contiamo all'indietro senza utilizzare un iteratore (altrimenti si otterrebbero errori che modificano l'elenco durante l'iterazione).

HashSet<T> ha anche sovraccarichi per l'uguaglianza dominante in caso di necessità.

Personalmente preferisco leggere dasblinkenlight's answer.

6

È possibile utilizzare HashSet per questo scopo (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(); 
    } 
} 

Quindi, se si scrive il proprio operatore di confronto, è possibile confrontare le stringhe un po 'diverso (come esempio, non 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(); 
    } 
} 

Poi nel codice:

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

o senza il vostro proprio confronto r:

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

Ora è possibile aggiungere elementi a hashSet e tutti gli elementi saranno univoci. Dopo aver finito con l'aggiunta di elementi è possibile convertirlo alla lista di nuovo:

var uniquedList = hashSet.ToList(); 

o semplicemente usare list.Distinct().ToList()

+0

Si noti che si finisce con un 'HashSet ' in questa istanza e non un 'Elenco '. Anche un 'Tuple ' non avrà bisogno di un fornitore di confronto. –

+0

La risposta è stata modificata, grazie –

+0

+1 Per l'alternativa in più. –