2017-06-21 8 views
1

Ich möchte eine gruppierte Liste der neuen, gelöschten, gemeinsamen Elemente erstellen. Ich mache es derzeit so:Gibt es eine effizientere Möglichkeit zum Erstellen einer gruppierten Liste

public class ListSortingGroupingTest 
{ 
    List<int> OldList = new List<int> { 1, 2, 3, 4, 5 }; 
    List<int> NewList = new List<int> { 3, 4, 5, 7, 8, 9 }; 

    public void CreateGroupedList() 
    { 
     var deleted = OldList.Except(NewList).Select(i => new { Group = "Deleted", Number = i }); 
     var added = NewList.Except(OldList).Select(i => new { Group = "Added", Number = i}); 
     var common = NewList.Intersect(OldList).Select(i => new { Group = "Common", Number = i}); 

     var result = deleted.Union(added).Union(common); 

    } 
} 

Dies funktioniert. Aber ich fragte mich, ob es einen besseren oder effizienteren Weg gab?

Schließlich möchte ich in einer WPF Grouped ListView daran binden.

Antwort

2

Ihr aktueller Ansatz ist der Standard und natürliche Art und Weise die Informationen für Änderungen zwischen altem und neuen Satz Extrahieren (d einzigartige Sequenz) von Werten. Die verwendeten LINQ-Mengenoperatoren (Except und Intersect) sind aufgrund der Hash-Lookup-basierten Implementierung recht effizient. Obwohl die 3 Aufrufe intern 3 Hash-Sets erzeugen, ist die Komplexität immer noch O(N+M). Die einzige Verbesserung wäre die Verwendung von Concat anstelle von Union, da die vorherigen Methoden die Werte eindeutig trennen würden.

Ein etwas effizienterer Weg (aber immer noch O(N+M)) könnte sein, die alten und neuen Elemente mit zusätzlichen Eigenschaften zu verketten, die angeben, ob der Wert alt oder neu ist, dann nach Wert gruppieren und die hinzugefügte/gelöschte/gemeinsame Statusbasis bestimmen Gruppierung und Inhalt - Gruppen mit 2 Werten sind die gemeinsamen und für Gruppen mit Einzelwert hängt das Hinzufügen/Löschen davon ab, ob der Wert neu oder alt ist:

var result = OldList.Select(x => new { Value = x, IsNew = false }) 
    .Concat(NewList.Select(x => new { Value = x, IsNew = true })) 
    .GroupBy(x => x.Value) 
    .Select(g => new 
    { 
     Group = g.Count() > 1 ? "Common" : g.First().IsNew ? "Added" : "Deleted", 
     Number = g.Key 
    }); 
+2

Fantastische Antwort und nachweislich effizienter. Ich habe eine Stoppuhr sowohl über meine als auch über Ihre Implementierung mit den folgenden Ergebnissen ausgeführt: ME => Ausführungszeit: 16954 (6ms) YOU => Ausführungszeit: 1321 (0ms) – John

0

Versuchen Sie es.

var result = OldList.Union(NewList).Select(n => new 
     { 
      Group = OldList.Contains(n) && NewList.Contains(n) ? "Common" : (OldList.Contains(n)) ? "Deleted" : "Added", 
      Number = n 
     }).ToList(); 
Verwandte Themen