2010-09-21 21 views
6

So che LINQ ha un metodo SequenceEquals. Questo metodo si assicura che ogni valore dell'oggetto in ciascuna raccolta corrisponda, nello stesso ordine.Esiste un metodo equivalente LINQ?

Quello che sto cercando è un tipo di funzionalità più "Equivalente". Solo che entrambe le sequenze contengono gli stessi elementi, non necessariamente nello stesso ordine.

Ad esempio, nUnit ha CollectionAssert.AreEqual() e CollectionAssert.AreEquivalent() che fa ciò che sto spiegando.

So che posso fare questo mediante:

  1. per l'ordine delle liste in anticipo e utilizzare SequenceEquals
  2. Utilizzando Intersect, poi vedere se l'intersezione è uguale alla sequenza originale.

Esempio:

var source = new[] {5, 6, 7}; 
source.Intersect(new[] {5, 7, 6}).Count() == source.Length; 
+1

C'è un errore nell'esempio di risposta. Devi confrontarlo con entrambi i conteggi altrimenti la tua funzione restituirebbe 'true' quando la fonte è un sottoinsieme di target. Cioè la fonte {5,6} e il target {5,7,6} – cellik

risposta

8

Vorrei creare un metodo di estensione che interseca e quindi confronta i conteggi.

+0

Hai la risposta per dandomi l'idea di confrontare i conteggi, quindi è stato bello e compatto, grazie! Assomiglia a questo: var source = new [] {5, 6, 7}; source.Intersect (new [] {5, 7, 6}). Count() == source.Length; – CubanX

+0

@CubanX: nota che se la fonte contiene duplicati, anche 'source.SetEquals (source)' restituirà false. –

+0

@Jon Buon punto, potrei dover inserire un distinto in là per garantire che non accadrà. – CubanX

9

Si potrebbe costruire un set e quindi utilizzare HashSet<T>.SetEquals. Non è strettamente collegato a LINQ, ma funziona bene con esso :)

Naturalmente, è possibile scrivere facilmente il proprio metodo di estensione per estenderlo. Qualcosa di simile a questo:

public static bool SetEquals<T>(this IEnumerable<T> source, IEnumerable<T> other) 
{ 
    HashSet<T> hashSet = new HashSet<T>(source); 
    return hashSet.SetEquals(other); // Doesn't recurse! Calls HashSet.SetEquals 
} 

EDIT: Come notato nei commenti, questo non tiene conto del numero di volte che si verificano elementi, così come l'ordine - così { 1, 2 } sarebbe "posto uguale" per { 1, 2, 1, 2, 1, 1, 1 }. Se non è quello che vuoi, diventerà un po 'più complicato.

+0

quindi 1,2 sarebbero "uguali" a 1,1,1,2,2,2? – spender

+0

@spender: per * set * uguaglianza, è corretto. L'insieme di elementi in ogni raccolta è lo stesso. Vale la pena evidenziare però - verrà modificato. –

+0

Jon, a volte in metodi come questo, non riesco a decidere se scriverlo come lo hai tu o fare qualcosa come 'HashSet hashSet = source come HashSet ?? nuovo HashSet (sorgente); '* potenzialmente * risparmio sul costo della costruzione di un nuovo' HashSet '. Hai un'opinione su questo? –

2

ho fatto in questo modo:

public static bool SetEquivalent<T>(
    this IEnumerable<T> aSet, 
    IEnumerable<T> anotherSet) 
{ 
    var diffA = aSet.Except(anotherSet).Count(); 
    var diffB = anotherSet.Except(aSet).Count(); 
    return diffA == diffB && diffA == 0; 
} 
Problemi correlati