Il modo più rapido per confrontare due elenchi generici per le differenze


214

Qual è il più veloce (e meno dispendioso in termini di risorse) per confrontare due enormi (> 50.000 articoli) e di conseguenza hanno due elenchi come quelli qui sotto:

  1. elementi che vengono visualizzati nel primo elenco ma non nel secondo
  2. elementi che vengono visualizzati nel secondo elenco ma non nel primo

Attualmente sto lavorando con List o IReadOnlyCollection e risolvo questo problema in una query linq:

var list1 = list.Where(i => !list2.Contains(i)).ToList();
var list2 = list2.Where(i => !list.Contains(i)).ToList();

Ma questo non funziona come vorrei. Qualche idea di rendere questo più veloce e meno dispendioso in termini di risorse di cui ho bisogno per elaborare un sacco di elenchi?

Risposte:


454

Utilizzare Except:

var firstNotSecond = list1.Except(list2).ToList();
var secondNotFirst = list2.Except(list1).ToList();

Ho il sospetto che ci siano approcci che in realtà sarebbero leggermente più veloci di così, ma anche questo sarà enormemente più veloce del tuo approccio O (N * M).

Se si desidera combinare questi, è possibile creare un metodo con quanto sopra e quindi un'istruzione return:

return !firstNotSecond.Any() && !secondNotFirst.Any();

Un punto da notare è che non v'è una differenza nei risultati tra il codice originale nella questione e la soluzione qui: tutti gli elementi duplicati che sono in una sola lista saranno riportati solo una volta con il mio codice, mentre avrebbero essere segnalati come molti volte in cui si verificano nel codice originale.

Ad esempio, con gli elenchi di [1, 2, 2, 2, 3]e [1], gli "elementi in elenco1 ma non in elenco2" risulteranno nel codice originale [2, 2, 2, 3]. Con il mio codice sarebbe solo [2, 3]. In molti casi questo non sarà un problema, ma vale la pena essere consapevoli.


8
Questo è davvero un enorme guadagno in termini di prestazioni! Grazie per questa risposta
Frank,

2
Mi chiedo due enormi elenchi, è utile ordinare prima di confrontare? o all'interno Tranne il metodo di estensione, l'elenco passato è già ordinato.
Larry,

9
@Larry: non è ordinato; costruisce un set di hash.
Jon Skeet,

2
@PranavSingh: Funzionerà per tutto ciò che ha l'eguaglianza appropriata - quindi se il tuo tipo personalizzato ha la precedenza Equals(object)e / o implementa IEquatable<T>dovrebbe andare bene.
Jon Skeet,

2
@ k2ibegin: utilizza il comparatore di uguaglianza predefinito, che utilizzerà IEquatable<T>un'implementazione o il object.Equals(object)metodo. Sembra che dovresti creare una nuova domanda con un esempio riproducibile minimo : non possiamo davvero diagnosticare le cose nei commenti.
Jon Skeet,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.