2010-09-21 16 views
6

Ich weiß, LINQ hat eine SequenceEquals Methode. Diese Methode stellt sicher, dass jeder Elementwert in jeder Sammlung in der gleichen Reihenfolge übereinstimmt.Gibt es eine LINQ-äquivalente Methode?

Was ich suche ist eine "äquivalente" Art der Funktionalität. Nur dass beide Sequenzen dieselben Elemente enthalten, nicht unbedingt in der gleichen Reihenfolge.

Zum Beispiel hat nUnit CollectionAssert.AreEqual() und CollectionAssert.AreEquivalent(), die tun, was ich erkläre.

Ich weiß, dass ich das tun kann entweder durch:

  1. Bestellen die Listen vor der Zeit und mit SequenceEquals
  2. Intersect verwendet, dann zu sehen, wenn der Schnittpunkt zu der ursprünglichen Sequenz entspricht.

Beispiel:

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

Es ist ein Fehler in dem Beispiel der Antwort. Sie müssen es mit beiden Werten vergleichen, andernfalls würde Ihre Funktion 'wahr' zurückgeben, wenn die Quelle eine Teilmenge des Ziels ist. I.e. Quelle {5,6} und Ziel {5,7,6} – cellik

Antwort

8

Ich würde eine Erweiterungsmethode erstellen, die den Schnittpunkt durchführt und dann die Anzahl vergleicht.

+0

Sie erhalten die Antwort für gab mir die Idee, die Zählungen zu vergleichen, so dass es schön und kompakt, danke! Sieht so aus: var source = new [] {5, 6, 7}; source.Intersect (new [] {5, 7, 6}). Count() == source.Length; – CubanX

+0

@CubanX: Beachten Sie, dass, wenn die Quelle irgendwelche Duplikate enthält, sogar "source.SetEquals (source)" false zurückgibt. –

+0

@Jon Guter Punkt, ich muss vielleicht ein distinct dort hineinwerfen, um sicherzustellen, dass das nicht passieren wird. – CubanX

9

Sie einen Satz bauen könnte und dann HashSet<T>.SetEquals verwenden. Es ist nicht strikt innerhalb von LINQ, aber es spielt gut damit :)

Natürlich könnten Sie leicht Ihre eigene Erweiterungsmethode schreiben, um dies zu erweitern. Etwas wie folgt aus:

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: Wie in den Kommentaren erwähnt, dies ignoriert die Anzahl der Elemente, sowie die Reihenfolge auftreten - so { 1, 2 } wäre „gleich“ zu { 1, 2, 1, 2, 1, 1, 1 }. Wenn Sie das nicht wollen, wird es etwas komplizierter.

+0

also 1,2 würde "gleich" 1,1,1,2,2,2? – spender

+0

@spender: Für * set * Gleichheit, das ist richtig. Die Menge der Elemente in jeder Sammlung ist gleich. Es lohnt sich aber hervorzuheben - wird bearbeitet. –

+0

Jon, manchmal in Methoden wie diesem, kann ich nicht entscheiden, ob Sie es so schreiben, wie Sie es haben oder etwas wie HashSet tun HashSet = source als HashSet ?? new HashSet (source); '* potenziell * spart die Kosten für den Bau eines neuen' HashSet '. Hast du eine Meinung dazu? –

2

Ich tat es auf diese Weise:

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; 
} 
Verwandte Themen