2017-02-17 1 views
1

Ich habe zwei Listenschnellster Weg passende Artikel aus zwei Listen C# zu bekommen

List1 Nur zwei Eigenschaft. Kann Wörterbuch nicht verwenden, da es möglicherweise doppelte Schlüssel gibt. Die Kombination von Property1 und Property2 ist einzigartig.

public class List1 
{ 
    public string Property1 { get; internal set; } 
    public string Property2 { get; internal set; } 
} 

public class List2 
{ 
    public string Property1 { get; internal set; } 
    public string Property2 { get; internal set; } 
    public string Property3 { get; internal set; } 
} 

List<List1> mylist1 = new List<List1>() { 
    new List1() {Property1="664",Property2="Ford" }, 
    new List1() {Property1="665",Property2="Ford" }, 
    new List1() {Property1="664",Property2="Toyota" }, 
}; 

List<List2> mylist2 = new List<List2>() { 
    new List2() {Property1="664",Property2="Ford" ,Property3="USA"}, 
    new List2() {Property1="665",Property2="Ford" ,Property3="USA"}, 
    new List2() {Property1="664",Property2="Toyota" ,Property3="USA"}, 
    new List2() {Property1="666",Property2="Toyota" ,Property3="USA"}, 
}; 

Ich brauche die passenden Artikel in mylist1 und mylist2. Die Übereinstimmung sollte nur für Property1 und Property2 auftreten. Property3 in der Mylist2 kann während des Vergleichs ignoriert werden.

Derzeit verwende ich

var matchingCodes = mylist1.Where(l1 => mylist2.Any(l2 => (l2.Property1 == l1.Property1 && l2.Property2==l1.Property2))).ToList(); 

, die perfekt funktioniert gut. Aber gibt es einen besseren Weg/schnellsten Weg, dies zu tun?

Ich kann List1 zu jedem anderen Typ ändern. aber nicht List2.

+0

Gangen Format konsistente Einzüge – Paparazzi

+0

LINQ ist selten die meisten und leistungsstark Option – Paparazzi

Antwort

2

Sie versuchen, set Operationen auf Ihre Datenlisten in LINQ zu tun. Es gibt vier LINQ-Funktionsaufrufe, mit denen Sie den aktuellen Code sauberer und prägnanter gestalten können. Diese Operationen sind:

  • Außer
  • Union
  • Intersect
  • Distinct

Die Sie suchen ist Intersect das ist

Gibt den Satz von Werten gefunden in zwei separaten Sammlungen identisch sein Source

Schließlich, wenn Sie immer die spezifischen Eigenschaften verwenden wollen Gleichheit erkennen und/oder Einzigartigkeit müssen Sie Equals für List1 und/oder List2 Klassen außer Kraft zu setzen. Dies hängt davon ab, wer auf der linken Seite der Schnittmenge (die Variable vor der.) Und wer auf der rechten Seite der Schnittmenge (die Variable, die an die Funktion übergeben wird) betrachtet wird.

Here is a SO answer wie Sie die Equals Funktion überschreiben, wenn Sie nicht wissen, wie Sie das tun. Zufälligerweise hat es auch ein Intersect Beispiel.

+0

Für OP Falls dies erforderlich wäre, würde dies jedoch eine benutzerdefinierte Implementierung von IEqualityComparer erfordern. Die auf dem anonymen Typ basierenden Join-Lösungen sind viel einfacher und flexibler. –

+0

Ich habe das bearbeitet, als ich vorher den Kommentar gesehen habe. Sollte jetzt da sein. Obwohl ich die Equals-Route ging. Außerdem wurde gefragt, ob es einen "besseren" Weg gäbe. Das ist sehr eigenwillig, da es einfacher ist, Code zu lesen als alle 'Join'-Antworten. –

0

Beide Eigenschaften sind Strings, so dass Sie nur ein Wörterbuch mit einem Schlüssel die Verkettung dieser Eigenschaften mit einem Wert von das tatsächliche Einzelteil erstellen können.

So für jedes Element in der anderen Liste einfach im Wörterbuch für die Verkettung ihrer Eigenschaft nachschlagen können, wenn es eine Übereinstimmung gibt, Sie vergleichen mit dem Einzelteil gefunden

+0

kann ich nicht woanders empfehlen, also ... Die ** schnellsten ** Ansätze sollten diese und die mit Sets vorgeschlagenen sein. Sets sind sauberer, aber Sie haben zwei verschiedene Arten von Objekten - wenn Sie das umgehen können - Sets verwenden. Denken Sie daran, GetHashcode zu überschreiben. Was ich schlage, sollte so schnell sein und würde nicht erfordern, dass Sie Änderungen an den tatsächlichen Klassen vornehmen. Ich kann kein Beispiel angeben - Ich habe VS nicht auf dieser Maschine installiert –

3

Der einfachste Weg, es zu tun in Linq, die relativ schnell ist, oder zumindest schneller als der Ansatz wird mit Join oder GroupJoin wie so:

List<List1> matchingCodes = mylist1.GroupJoin(mylist2, 

       l1 => new { l1.Property1, l1.Property2 },// Define how the key from List1 looks like 
       l2 => new { l2.Property1, l2.Property2 },// Define how the key from List2 looks like 

       // Define what we select from the match between list1 and list2 
       (l1Item, l2Items) => l1Item).ToList(); 

vereinfacht, das schafft zwei Wörterbücher, die dann zusammengefügt werden.

GroupJoin funktioniert hier besser, da es Ihnen den Artikel aus List1 und alle passenden aus List2 gibt.

Eine reguläre Join würde das gleiche Element aus Liste1 pro Spiel von List2 zurückgeben.

Siehe Enumerable.GroupJoin (C# Reference)

Beachten Sie auch dies das Äquivalent zu @octavioccl's answer ist. Auch in diesem Beispiel wird davon ausgegangen, dass die Namen der Eigenschaften aus beiden Klassen gleich sind. Wenn sie Arent Sie zu modifizieren haben keyselectors sie abit wie so:

l1 => new { A=l1.Foo, B=l1.Bar}, 
l2 => new { A=l2.Herp, B=l2.Derp}, 
+1

Ich habe einen schnellen Benchmark mit meiner Methode und der oben vorgeschlagenen Methode gemacht. Meine Methode - 54ms. vorgeschlagen - 112 ms – Gokul

+1

@ Gokul, die wirklich von der Menge der Elemente in diesen Listen abhängt. Wenn die Anzahl klein ist, hat der Join wahrscheinlich mehr Overhead, um diese Hashtabellen zu erstellen, bevor er seine Arbeit erledigt. Meine Antwort nahm auch an, dass Ihre Listen mehr als ein paar Punkte enthalten, ansonsten wäre es nicht sinnvoll, nach einer performanteren Lösung zu fragen. – CSharpie

+0

mylist1 kann mehr als 1000-10,000 Elemente enthalten. aber mylist2 wird 1-10 Elemente haben. – Gokul

3

Sie könnten auch eine trete:

var query= from l in mylist1 
      join e in mylist2 on new {Property1=l.Property1,Property2=l.Property2} equals new {Property1=e.Property1,Property2=e.Property2} 
      select l; 
+0

Sie können die 'Namen' weglassen, die es ein bisschen lesbarer machen, denke ich. 'neue {Property1 = l.Property1, Property2 = l.Property2}' => 'neue {l.Property1, l.Property2}' – CSharpie

+0

Dank @CSharpie, ich bin mir dessen bewusst, aber wenn die Namen der Eigenschaft unterschiedlich sind zwischen diesen beiden Klassen ist es notwendig, es auf diese Weise zu tun. Ich gehe davon aus, dass das nicht die richtigen Namen sind, aber wenn sie mit den Namen übereinstimmen, können Property-Namen in den anonymen Typen weggelassen werden. – octavioccl

+0

Sie haben Recht, das macht Ihre Antwort wasserdichter. – CSharpie

Verwandte Themen