2010-04-01 5 views
8

ho 2 oggetti lista:Cercando di ottenere valori distinti da due Lista <int> oggetti

List<int> lst1 = new List<int>(); 
List<int> lst2 = new List<int>(); 

Diciamo che hanno valori:

lst1.Add(1); 
lst1.Add(2); 
lst1.Add(3); 
lst1.Add(4); 

lst2.Add(1); 
lst2.Add(4); 

Ho bisogno di ottenere un oggetto che contiene il "distinto" elenco di entrambi; quindi in questo caso il ritorno sarebbe List {2, 3}.

C'è un modo semplice per farlo? O devo scorrere ogni valore degli elenchi e confrontare?

Sono aperto all'utilizzo di ObjectQuery, LINQ, ecc. Poiché questi elenchi provengono da un database e potrebbero essere potenzialmente diverse da centinaia a diverse migliaia di voci.

Grazie!

+0

I vostri elenchi ordinati, o è solo una coincidenza in questo esempio? – Thomas

+0

Non sarebbe meglio modificare lo Sql? perché spostare gli oggetti indesiderati attraverso il filo? – eschneider

+1

Il tuo obiettivo non è chiaro. Nel tuo esempio, lst2 è una sovrapposizione perfetta di lst1. È una garanzia? Supponiamo che lst2 contenga anche '5', quale sarebbe il risultato desiderato: {2,3} o {2,3,5}? –

risposta

13

Ahmad ha quasi ragione con Except, credo, ma questo non ti darà gli articoli che sono in lst2 ma non in lst1. Quindi nell'esempio che hai dato, se hai aggiunto 5 a lst2, immagino che tu voglia che il risultato sia {2, 3, 5}. In tal caso, vuoi una differenza simmetrica. Io non so pensare c'è un modo per farlo direttamente in LINQ agli Oggetti in una singola chiamata, ma puoi ancora realizzarlo. Ecco un modo semplice ma inefficiente per farlo:

lst1.Union(lst2).Except(lst1.Intersect(lst2)).ToList(); 

(Ovviamente è solo bisogno ToList() se si ha sinceramente bisogno di un List<T> invece di un IEnumerable<T>.)

Il modo per leggere questo è "Voglio elementi che si trovano in entrambi gli elenchi ma non in entrambi".

È possibile che sarebbe più efficace utilizzare Concat - che sarebbe comunque funzionare come Except è un operatore basato set che restituirà solo risultati distinte:

lst1.Concat(lst2).Except(lst1.Intersect(lst2)).ToList(); 
+0

@Jon diresti che il tuo approccio è più veloce del mio? Ho fatto un rapido mini-benchmark e sembra così, anche se probabilmente trascurabile nel più grande schema di cose. Immagino che il "Concat" aiuti contro l'uso di "Union". –

+0

@Ahmad: Beh, usando Concat sto facendo solo due operazioni invece di tre ... ci vorrebbe un bel po 'di lavoro per analizzarlo, penso. Penso che la mia risposta sia più semplice da capire - anche se suppongo che ... –

+0

sia abbastanza buono per me. È logico che il numero di operazioni impostate probabilmente contribuisca a farlo poiché viene svolto più lavoro per determinare quali valori corrispondono per ciascuna rispettiva operazione. Grazie! –

1

Se i risultati provengono dal database, sarebbe meglio elaborarli lì. Sarà molto più veloce rispetto al funzionamento in memoria, soprattutto se ci sono molti risultati.

Se è necessario elaborarli nel codice, è possibile utilizzare i4o - Indexed LINQ per renderlo più veloce.

6

MODIFICA: Grazie ai commenti è necessario fare qualche lavoro extra oltre all'uso di Except per ottenere una differenza simmetrica. Se un valore addizionale viene aggiunto al secondo elenco Tranne solo non sarebbe corretto. Per ottenere il risultato corretto provare questo:

var list1 = new List<int>(Enumerable.Range(1,4)); 
var list2 = new List<int> { 1, 4, 6 }; 

var result = list1.Except(list2).Union(list2.Except(list1)); 

Le suddette dichiarazioni {2, 3, 6}.

Si noti che è necessario aggiungere un ToList() se si ha realmente bisogno di un List<int>, altrimenti l'operazione sopra riportata restituirà un IEnumerable<int>.


Utilizzare i Enumerable.Except method, che produce la differenza set di due sequenze:

var result = lst1.Except(lst2); 
+4

Funziona su questo esempio, ma "Tranne" fornisce la differenza di set, non la differenza simmetrica. In particolare, 'lst2.Except (lst1)' darebbe una risposta diversa (la lista vuota). – Thomas

+0

In questo caso, la risposta effettiva sarebbe l'unione di 'lst1.Except (lst2)' e 'lst2.Except (lst1)' ... –

+0

Concordato con @Thomas, questo non è completamente ciò che l'OP voleva. Vuole sapere quali oggetti sono distinti nel set. – casperOne

-1

in LINQ:

var distinct = lst2.Contact(lst1).Distinct().ToList(); 

(la tua spiegazione sembra dire che si vuole gli elementi univoci in entrambe le liste, ma il tuo esempio sembra che tu voglia il union di entrambi gli elenchi).

+0

Questo non risolve affatto la domanda. Non chiede gli elementi distinti in ciascuna lista, né chiede un'unione. Vuole il contrario di un'intersezione, che è "Eccetto". –

+0

Dice "Ho bisogno di ottenere un oggetto contenente la lista" distinta "di entrambi". La mia interpretazione è di tutti gli elementi in entrambe le liste. Tuttavia il suo esempio è contraddittorio. – Keltex

+0

Mi affiderei all'OP esprimendo il suo desiderio in una descrizione piuttosto che nell'uso corretto dei termini. –

0

LINQ sarebbe il modo più semplice, raggruppare ciascun elemento basato sul suo valore e quindi selezionando solo quelli che hanno un elemento:

from i in lst1.Concat(lst2) 
group i by i into g 
where !g.Skip(1).Any() 
select g.Key; 

Utilizzando Spostati qui vi permetterà di fare in modo che non più di un elemento esiste; se nella sequenza sono presenti 1 o meno elementi, viene restituita una sequenza vuota, in cui Any restituirà false.

0

Solo che -

var distinct = a.Union(b); 
Problemi correlati