it-swarm.com.de

Prüfen Sie, ob ein Array eine Teilmenge eines anderen ist

Irgendeine Idee, wie man prüft, ob diese Liste eine Untermenge einer anderen ist?

Konkret habe ich

List<double> t1 = new List<double> { 1, 3, 5 };
List<double> t2 = new List<double> { 1, 5 };

Wie kann man überprüfen, dass T2 eine Untermenge von T1 ist, unter Verwendung von LINQ?

131
Graviton
bool isSubset = !t2.Except(t1).Any();
235

Verwenden Sie HashSet anstelle von List, wenn Sie mit Sets arbeiten. Dann können Sie einfach IsSubsetOf () verwenden.

HashSet<double> t1 = new HashSet<double>{1,3,5};
HashSet<double> t2 = new HashSet<double>{1,5};

bool isSubset = t2.IsSubsetOf(t1);

Entschuldigung, dass LINQ nicht verwendet wird. :-(

Wenn Sie Listen verwenden müssen, funktioniert die Lösung von @ Jared unter dem Vorbehalt, dass Sie alle vorhandenen Elemente entfernen müssen.

52
tvanfosson

Wenn Sie unit-testing sind, können Sie auch die CollectionAssert.IsSubsetOf -Methode verwenden:

CollectionAssert.IsSubsetOf(subset, superset);

Im obigen Fall würde dies bedeuten:

CollectionAssert.IsSubsetOf(t2, t1);
9
Géza

@ Camerons Lösung als Erweiterungsmethode:

public static bool IsSubsetOf<T>(this IEnumerable<T> a, IEnumerable<T> b)
{
    return !a.Except(b).Any();
}

Verwendungszweck:

bool isSubset = t2.IsSubsetOf(t1);

(Dies ist ähnlich, aber nicht ganz dasselbe wie auf @ Michaels Blog.)

6
Neil

Dies ist eine wesentlich effizientere Lösung als die hier aufgeführten, insbesondere die Top-Lösung:

bool isSubset = t2.All(elem => t1.Contains(elem));

Wenn Sie in t2 ein einzelnes Element finden können, das nicht in t1 ist, wissen Sie, dass t2 keine Untermenge von t1 ist. Der Vorteil dieser Methode besteht darin, dass sie im Gegensatz zu den Lösungen, die .Except oder .Intersect verwenden, vollständig vor Ort ausgeführt wird, ohne zusätzlichen Speicherplatz zuzuweisen. Darüber hinaus ist diese Lösung in der Lage zu brechen, sobald sie ein einzelnes Element findet, das die Teilmengenbedingung verletzt, während die anderen weiter suchen. Nachfolgend sehen Sie die optimale Langform der Lösung, die in meinen Tests nur unwesentlich schneller ist als die obige Abkürzungslösung.

bool isSubset = true;
foreach (var element in t2) {
    if (!t1.Contains(element)) {
        isSubset = false;
        break;
    }
}

Ich habe einige rudimentäre Leistungsanalysen aller Lösungen durchgeführt und die Ergebnisse sind drastisch. Diese beiden Lösungen sind etwa 100x schneller als die Lösungen .Except () und .Intersect () und benötigen keinen zusätzlichen Speicher. 

5
user2325458

Aufbauend auf den Antworten von @Cameron und @Neil habe ich eine Erweiterungsmethode geschrieben, die dieselbe Terminologie wie die Enumerable-Klasse verwendet.

/// <summary>
/// Determines whether a sequence contains the specified elements by using the default equality comparer.
/// </summary>
/// <typeparam name="TSource">The type of the elements of source.</typeparam>
/// <param name="source">A sequence in which to locate the values.</param>
/// <param name="values">The values to locate in the sequence.</param>
/// <returns>true if the source sequence contains elements that have the specified values; otherwise, false.</returns>
public static bool ContainsAll<TSource>(this IEnumerable<TSource> source, IEnumerable<TSource> values)
{
    return !values.Except(source).Any();
}
0
sclarke81

Hier überprüfen wir, ob ein Element in der untergeordneten Liste (d. H. t2) vorhanden ist, das nicht in der übergeordneten Liste (d. H. t1) enthalten ist

z.B:

bool isSubset = !(t2.Any(x => !t1.Contains(x)));
0
Lucifer