2017-06-22 4 views
0

Betrachten Sie, ich habe Objekte Foo und Bar; und 3 Tupel genannt A, B und C.Tupel vergleichen, Ignorieren Reihenfolge der Elemente

A = (Foo, Bar) 
B = (Bar, Foo) 
C = (Foo, Bar) 

ich wissen wollen, ob ihre Elemente die gleiche, nicht die Ordnung der Elemente zu berücksichtigen sind. So sind meine gewünschten Ergebnisse;

A.HasSameElementsWith(B) -> True 
A.HasSameElementsWith(C) -> True 
B.HasSameElementsWith(C) -> True 

Ich weiß, dass ich eine verschachtelte Schleife ausführen kann, um sie für jedes ihrer Elemente zu vergleichen. Etwas entlang der Linien von:

foreach (itemA in A) 
{ 
    bool flag = false; 

    foreach (itemB in B) 
    { 
     if(itemA == itemB) 
     { 
      flag = true; 
      break; 
     } 
    } 

    if (!flag) return false; 
} 

return true; 

Aber das scheint ineffizient. Gibt es einen bequemeren Weg, dies zu tun?


Hinweis:

ich Generika bin mit, so Foo und Bar kann von jeder Art sein. Aber sie werden den gleichen Typ miteinander haben. (d. h. Der Typ von Foo wird der gleiche sein wie der Typ Bar)

+0

Sortieren oder Nachschlagen ist der übliche Weg, um Dinge zu beschleunigen – doctorlove

+0

@doctorlove Sorting auch meine Gedanken gekreuzt, aber was meinst du mit Nachschlagen? Ich würde es begrüßen, wenn Sie es ausarbeiten. –

+0

Sie wissen, dass Ihre '==' Referenzen nur dann nicht vergleichen, wenn sie gleich sind –

Antwort

4

Wenn Sie zwei 2-Tupel, dann gibt es nur zwei Möglichkeiten, um sie gleich sein nach Ihren Regeln und Sie können schreiben, dass als fast Einzeiler Methode:

public static bool HasSameElementsWith<T>(this (T, T) tuple1, (T, T) tuple2) => 
    (Equals(tuple1.Item1, tuple2.Item1) && Equals(tuple1.Item2, tuple2.Item2)) || 
    (Equals(tuple1.Item1, tuple2.Item2) && Equals(tuple1.Item2, tuple2.Item1)); 

Wenn Sie mehr als zwei Elemente pro Tupel haben können, würde ich anfangen, sie als eine Sammlung zu betrachten, und die Frage wird dann, wenn zwei Sammlungen dieselben Elemente haben. Um das zu tun, können Sie jedes Element in der ersten Sammlung in einer Dictionary<T, int> zählen und dann die Elemente aus der zweiten Sammlung herunter zählen. Wenn beide Sammlungen dieselben Elemente enthalten, sollten alle Zählungen am Ende null sein. (Wenn Sie sicher, dass Elemente in jeder Kollektion sind einzigartig sind, könnten Sie HashSet<T> stattdessen verwenden.) In Code:

public static bool HasSameElementsWith<T>(
    this IEnumerable<T> collection1, IEnumerable<T> collection2) 
{ 
    var counts = new Dictionary<T, int>(); 

    foreach (var item in collection1) 
    { 
     counts.TryGetValue(item, out int count); 
     count++; 
     counts[item] = count; 
    } 

    foreach (var item in collection2) 
    { 
     counts.TryGetValue(item, out int count); 
     if (count == 0) 
      return false; 
     count--; 
     counts[item] = count; 
    } 

    return counts.Values.All(c => c == 0); 
} 

Jetzt können Sie die Tupel-Version von HasSameElementsWith auf der Oberseite der Sammlung Version implementieren:

public static bool HasSameElementsWith<T>(this (T, T) tuple1, (T, T) tuple2) => 
    HasSameElementsWith(tuple1.ToArray(), tuple2.ToArray()); 

public static T[] ToArray<T>(this (T, T) tuple) => new[] { tuple.Item1, tuple.Item2 }; 
0

Ich werde @doctorlove Kommentar ein wenig exapnd. Er erwähnte das Sortieren. Sobald Sie es sortiert haben, können Sie sie Element für Element vergleichen. Pseudo-Code:

public bool Compare(A, B){ 
    return (A[1] == B[1] & A[2] == B[2]); 
} 
Verwandte Themen