2015-05-18 10 views
5

Qui ci sono due liste:Come confrontare due liste <object> in C# e conservare solo gli elementi che non hanno duplicati?

var list1 = new List<UserGroupMap> 
     { 
      new UserGroupMap { UserId = "1", GroupId = "1", FormGroupFlag = "1", GroupDescription = "desc1", GroupName = "g1"}, 
      new UserGroupMap { UserId = "1", GroupId = "2", FormGroupFlag = "1", GroupDescription = "desc1", GroupName = "g1"}, 
      new UserGroupMap { UserId = "1", GroupId = "3", FormGroupFlag = "1", GroupDescription = "desc1", GroupName = "g1"}, 
      new UserGroupMap { UserId = "2", GroupId = "3", FormGroupFlag = "1", GroupDescription = "desc1", GroupName = "g1"} 
     }; 

     var list2 = new List<UserGroupMap> 
     { 
      new UserGroupMap { UserId = "1", GroupId = "1", FormGroupFlag = "1", GroupDescription = "desc1", GroupName = "g1"}, 
      new UserGroupMap { UserId = "1", GroupId = "2", FormGroupFlag = "1", GroupDescription = "desc1", GroupName = "g1"}, 
      new UserGroupMap { UserId = "1", GroupId = "3", FormGroupFlag = "1", GroupDescription = "desc1", GroupName = "g1"}, 
      new UserGroupMap { UserId = "2", GroupId = "3", FormGroupFlag = "1", GroupDescription = "desc1", GroupName = "g1"}, 
      new UserGroupMap { UserId = "4", GroupId = "3", FormGroupFlag = "1", GroupDescription = "desc1", GroupName = "g1"}, 
      new UserGroupMap { UserId = "3", GroupId = "3", FormGroupFlag = "1", GroupDescription = "desc1", GroupName = "g1"}, 
     }; 

ora quello che voglio che accada è quello di ottenere una lista che non ha i duplicati, confrontare fondamentalmente List1 e List2 restituire solo gli elementi che sono duplicati.

in base all'esempio, ciò che deve restituire sono gli ultimi due elementi dell'elenco 2 poiché non sono in elenco1.

+0

Le risposte di seguito sono corrette, ma è importante pensare a cosa intendi esattamente * duplicando. Ad esempio prendi 'var a = new UserGroupMap {UserId =" 1 ", GroupId =" 1 ", FormGroupFlag =" 1 "}; var b = new UserGroupMap {UserId = "1", GroupId = "1", FormGroupFlag = "1"}; 'la nuova Lista (a, b) contiene duplicati? Che dire dopo la chiamata b.GroupId = "2"? – Martijn

risposta

4

Fondamentalmente, il compito può essere risolto con Linq utilizzando

var Result = list1.Concat(list2).Except(list1.Intersect(list2)); 

tuttavia questo richiede probabilmente UserGroupMap per implementare l'interfaccia IEquatable<UserGroupMap> in modo opportuno, a meno UserGroupMap è un struct. Se l'implementazione di IEquatable<UserGroupMap> per qualche motivo è impossibile, è possibile utilizzare lo overload di Except che accetta un confronto personalizzato come argomento, nonché lo overload di Intersect che accetta un confronto personalizzato come argomento.

+0

In che modo si preoccupa di "conservare solo gli articoli che non hanno duplicati"? – Maarten

+0

@Maarten Grazie per il commento; Ho corretto la risposta. – Codor

+0

@TimSchmelter Mi sono sbagliato, ma ho aggiornato la risposta. – Codor

5

Prova questa

list2.Except(list1).Concat(list1.Except(list2)); 
+2

Questo non funziona finché UserGroupMap non sovrascrive 'Equals' e' GetHashCode'. Non è nemmeno chiaro in che modo "restituisce gli ultimi due elementi dalla lista 2 che non sono in elenco1". –

+0

Supponendo che tu gestisca l'uguaglianza da qualche parte, perché il '.Distinct()'? E perché il '.Union (...)' invece di '.Concat (...)'? L'OP non ha menzionato la rimozione dei duplicati da "sé". – Maarten

+0

@ Maarten, grazie per aver segnalato i problemi – Yohannes

1

quello che deve restituire sono gli ultimi due elementi da elenco 2 dal momento che non sono in lista1.

aggiornamento Se non è possibile utilizzare LINQ si potrebbe usare un HashSet<T> di cercare e rimuovere i duplicati. Devi eseguire l'override GetHashCode e Equals (o implementare IEquatable<T> quello che ho fatto):

public class UserGroupMap : IEquatable<UserGroupMap> 
{ 
    public string UserId {get;set;} 
    public string GroupId { get; set; } 
    public string FormGroupFlag { get; set; } 
    public string GroupDescription { get; set; } 
    public string GroupName { get; set; } 

    public override int GetHashCode() 
    { 
     unchecked 
     { 
      int hash = 17; 

      hash = hash * 23 + (UserId ?? "").GetHashCode(); 
      hash = hash * 23 + (GroupId ?? "").GetHashCode(); 
      hash = hash * 23 + (FormGroupFlag ?? "").GetHashCode(); 
      hash = hash * 23 + (GroupDescription ?? "").GetHashCode(); 
      hash = hash * 23 + (GroupName ?? "").GetHashCode(); 

      return hash; 
     } 
    } 

    public bool Equals(UserGroupMap other) 
    { 
     if(other == null) return false; 
     if(Object.ReferenceEquals(this, other)) return true; 

     return this.UserId == other.UserId 
      && this.GroupId == other.GroupId 
      && this.FormGroupFlag == other.FormGroupFlag 
      && this.GroupDescription == other.GroupDescription 
      && this.GroupName == other.GroupName; 
    }  
} 

Ora è facile:

var uniqueInList2 = new HashSet<UserGroupMap>(list2); 
uniqueInList2.ExceptWith(list1); 

Risultato: i tuoi due oggetti desiderati da list2.

Si noti che questo approccio rimuove anche i duplicati da list2, non sono sicuro se lo si desidera.


Vecchia risposta:

var onlyInTwo = list2 
    .Where(x => !list1.Any(x2 => x.UserId == x2.UserId && x.FormGroupFlag == x2.FormGroupFlag && x.GroupDescription == x2.GroupDescription && x.GroupName == x2.GroupName)); 

Si potrebbe anche implementare un costume IEqalityComparer<UserGroupMap> che può essere utilizzato ad esempio in Enumerable.Except. Allora è semplice ed efficace:

var onlyInTwo = list2.Except(list1, new UserGroupMapComparer()); 

Un altro modo è lasciare UserGroupMap esclusione Equals e GetHashCode o per l'attuazione del IEquatable<UserGroupMap> interface.

+0

In realtà voglio farlo senza usare linq e attualmente sto lottando hai qualche idea su come farlo? Oh grazie per la prima soluzione che hai fornito funziona davvero, anche se in realtà ho bisogno di qualcosa che non usa linq. Grazie! –

+0

@ randelramirez1: ho aggiornato la mia risposta. –

+0

@TimSchmelter Stavo aggiornando la mia risposta con l'implementazione di 'GetHashCode()' e poi vedo che il tuo è lo stesso con il mio. Quindi, non pensare che sia una copia :) –

1

computer non sa come mettere a confronto le istanze di classe personalizzati.Avete alcune scelte e uno di loro è quello di creare il proprio operatore di confronto che deve implementare IEqualityComparer<T> interfaccia:

sealed class MyComparer : IEqualityComparer<UserGroupMap> 
{ 
    public bool Equals(UserGroupMap x, UserGroupMap y) 
    { 
     if (x == null) 
      return y == null; 
     else if (y == null) 
      return false; 
     else 
      return x.UserId.Equals(y.UserId) 
       && x.GroupId.Equals(y.GroupId) 
       && x.FormGroupFlag.Equals(y.FormGroupFlag) 
       && x.GroupDescription.Equals(y.GroupDescription) 
       && x.GroupName.Equals(y.GroupName); 
    } 

    public int GetHashCode(UserGroupMap obj) 
    { 
     unchecked 
     { 
      int hash = 17; 

      hash = hash * 23 + (obj.UserId ?? "").GetHashCode(); 
      hash = hash * 23 + (obj.GroupId ?? "").GetHashCode(); 
      hash = hash * 23 + (obj.FormGroupFlag ?? "").GetHashCode(); 
      hash = hash * 23 + (obj.GroupDescription ?? "").GetHashCode(); 
      hash = hash * 23 + (obj.GroupName ?? "").GetHashCode(); 

      return hash; 
     } 
    } 
} 

e quindi utilizzare Except() dal System.Linq spazio dei nomi per trovare la differenza di due sequenze utilizzando l'operatore di confronto uguaglianze predefinito:

var result = list2.Except(list1, new MyComparer()).ToList(); 
0

non è chiaro dalla domanda se si desidera:

1: i risultati di lista2 che non sono in lista1, come nel piccolo campione impostare esempio:

quello che deve restituire sono gli ultimi due elementi da elenco 2 in quanto non sono in lista1

o 2: se si desidera trovare i non duplicati da entrambe le liste

per ottenere una lista che non ha i duplicati

o 3: se si desidera trovare i duplicati da entrambe le liste

fondamentalmente confronta lista1 e lista2 restituiscono solo gli elementi che sono duplicati.

3: è banale, quindi probabilmente non che:

list1.Concat(list2).Duplicate(new UserGroupMap()); 

Supponendo che hai aggiunto al tuo IEqualityComparer UserGroupMap (o è stato aggiunto come un operatore di confronto separato).

1: è stato risposto

2: non è stato risposto, così qui si va:

var result = (from item in list1.Concat(list2) 
       group item by new { item.UserId, item.GroupId, item.FormGroupFlag, item.GroupDescription, item.GroupName } 
       into groups 
       where groups.Count() == 1 
       select groups) 
      .SelectMany(x => x); 

Questo sarà quindi funzionare anche se si scambia il contenuto di Lista1 e Lista2.

Problemi correlati