Haben Sie eine Idee, wie Sie überprüfen können, ob diese Liste eine Teilmenge einer anderen ist?
Insbesondere habe ich
List<double> t1 = new List<double> { 1, 3, 5 };
List<double> t2 = new List<double> { 1, 5 };
Wie kann mit LINQ überprüft werden, ob t2 eine Teilmenge von t1 ist?
Antworten:
quelle
Verwenden Sie HashSet anstelle von List, wenn Sie mit Sets arbeiten. Dann können Sie einfach IsSubsetOf () verwenden
Entschuldigung, dass LINQ nicht verwendet wird. :-(
Wenn Sie Listen verwenden müssen, funktioniert die Lösung von @ Jared mit der Einschränkung, dass Sie alle vorhandenen wiederholten Elemente entfernen müssen.
quelle
Wenn Sie Unit-Tests durchführen , können Sie auch die CollectionAssert.IsSubsetOf- Methode verwenden:
Im obigen Fall würde dies bedeuten:
quelle
Dies ist eine wesentlich effizientere Lösung als die anderen hier veröffentlichten, insbesondere die Top-Lösung:
Wenn Sie in t2 ein einzelnes Element finden, das nicht in t1 enthalten ist, wissen Sie, dass t2 keine Teilmenge von t1 ist. Der Vorteil dieser Methode besteht darin, dass sie im Gegensatz zu den Lösungen mit .Except oder .Intersect direkt vor Ort durchgeführt wird, ohne zusätzlichen Speicherplatz zuzuweisen. Darüber hinaus kann diese Lösung unterbrochen werden, sobald ein einzelnes Element gefunden wird, das gegen die Teilmengenbedingung verstößt, während die anderen weiter suchen. Unten ist die optimale Langform der Lösung aufgeführt, die in meinen Tests nur unwesentlich schneller ist als die obige Kurzlösung.
Ich habe eine rudimentäre Leistungsanalyse aller Lösungen durchgeführt, und die Ergebnisse sind drastisch. Diese beiden Lösungen sind etwa 100-mal schneller als die Lösungen .Except () und .Intersect () und verwenden keinen zusätzlichen Speicher.
quelle
!t2.Except(t1).Any()
macht es. Linq arbeitet hin und her.Any()
fragt ein,IEnumerable
ob es mindestens ein Element gibt. In diesem Szenariot2.Except(t1)
wird nur das erste Element ausgegeben, vont2
dem nicht vorhanden istt1
. Wenn das erste Elementt2
ist nicht int1
es am schnellsten beendet, wenn alle Elementet2
sind int1
dem längsten läuft.t1={1,2,3,...9999}
undt2={9999,9998,99997...9000}
die folgenden Messungen erhalten :!t2.Except(t1).Any(): 1ms -> t2.All(e => t1.Contains(e)): 702ms
. Und es wird schlimmer, je größer die Reichweite ist.t2.Except (t1)
kehrt einIEnumerable
nicht einCollection
. Es werden nur dann alle möglichen Elemente ausgegeben, wenn Sie vollständig darüber iterieren, z. B. durchToArray ()
oderToList ()
oder verwenden,foreach
ohne das Innere zu beschädigen. Suchen Sie nach einer verzögerten Ausführung von linq , um mehr über dieses Konzept zu erfahren .t2={1,2,3,4,5,6,7,8}
t1={2,4,6,8}
t2.Except(t1)
=> erstes Element von t2 = 1 => Differenz von 1 zu t1 ist 1 (geprüft gegen {2,4,6,8}) =>Except()
emittiert erstes Element 1 =>Any()
erhält ein Element =>Any()
ergibt true => keine weitere Überprüfung der Elemente in t2.@ Camerons Lösung als Erweiterungsmethode:
Verwendung:
(Dies ist ähnlich, aber nicht ganz das gleiche wie das, das auf @ Michaels Blog gepostet wurde.)
quelle
Aufbauend auf den Antworten von @Cameron und @Neil habe ich eine Erweiterungsmethode geschrieben, die dieselbe Terminologie wie die Enumerable-Klasse verwendet.
quelle
z.B:
quelle
Versuche dies
Die Idee hier ist, dass Intersect nur die Werte zurückgibt, die sich in beiden Arrays befinden. Wenn zu diesem Zeitpunkt die Länge der resultierenden Menge mit der ursprünglichen Menge übereinstimmt, befinden sich alle Elemente in "Menge" ebenfalls in "Prüfung", und daher ist "Menge" eine Teilmenge von "toCheck".
Hinweis: Meine Lösung funktioniert nicht, wenn "set" Duplikate enthält. Ich ändere es nicht, weil ich nicht die Stimmen anderer Leute stehlen will.
Hinweis: Ich habe für Camerons Antwort gestimmt.
quelle