LINQ Group By in ein Dictionary-Objekt

161

Ich versuche, LINQ zu verwenden, um ein Dictionary<string, List<CustomObject>>aus einem zu erstellen List<CustomObject>. Ich kann dies mit "var" zum Laufen bringen, aber ich möchte keine anonymen Typen verwenden. Hier ist was ich habe

var x = (from CustomObject o in ListOfCustomObjects
      group o by o.PropertyName into t
      select t.ToList());

Ich habe auch versucht, Cast<>()die LINQ-Bibliothek zu verwenden, sobald ich sie habe x, aber ich bekomme Kompilierungsprobleme, die dazu führen, dass es sich um eine ungültige Besetzung handelt.

Atari2600
quelle
Was ist, wenn Sie var x = versuchen (aus CustomObject o in der ListOfCustomObjects-Gruppe o von o.PropertyName in t select t) .ToList ();
Esastincy
44
Gibt es einen Grund, warum Sie dies tun müssen, anstatt ToLookup zu verwenden, das dafür entwickelt wurde?
Jon Skeet
1
Jon, kannst du bitte ein Beispiel dafür posten, wie ToLookup in dieser Situation funktioniert? Ich bin mit dieser LINQ-Methode nicht vertraut.
Atari2600
8
@ JonSkeet Du bist großartig! (Ich meine, das wussten alle schon, aber immer noch.) Der Grund, warum ich nicht vorhatte, ToLookup zu verwenden, war, dass ich bis jetzt noch nie davon gehört hatte. Jetzt weiß ich!
Neminem
1
Der Vollständigkeit halber wird bei der Verwendung varkein "anonymer" Typ verwendet, sondern ein "impliziter" Typ. Anonyme Typen sind neue Klassen, die vom Compiler erstellt wurden, um die Konstruktion zu handhaben new { thing = "stuff" };. Implizite Typen sind vorhandene Klassen. Dies varist nur eine bequeme Möglichkeit, sie zu referenzieren, wenn die Variable sofort zugewiesen wird. Der Variablentyp kann aus dem Typ des ihr zugewiesenen Objekts abgeleitet werden. Sie können sogar implizit eine Variable eingeben, die auf einen anonymen Typ verweist, dh:var a = new { thing = "stuff" };
Michael Blackburn

Antworten:

349
Dictionary<string, List<CustomObject>> myDictionary = ListOfCustomObjects
    .GroupBy(o => o.PropertyName)
    .ToDictionary(g => g.Key, g => g.ToList());
Yuriy Faktorovich
quelle
6
Sofern Sie keine Eigenschaft von 'CustomObject' als Listenwert benötigen (in dieser Antwort nicht angezeigt), sollten Sie den Kommentar von Jon Skeet zu der Frage, die ToLookup () empfiehlt, überprüfen.
Shaun
3
Dies ist der Weg, wenn ein nicht unveränderliches Ergebnis gewünscht wird. ToLookup ist unveränderlich.
Amit
1
Meine 2 Cent (nur weil ich eine Stunde lang Probleme hatte :)): Wenn Sie nach einer Eigenschaft gruppieren, stellen Sie sicher, dass die Eigenschaft einen Wert hat! Andernfalls schlägt die Todict-Methode fehl, den Schlüssel zu generieren (mindestens für String-Eigenschaften ...) :)
dba
.GroupBy(o => o.PropertyName).ToDictionary(g => g.Key, g => g.ToList())Dies könnte Teil der Erweiterung der Linq-Bibliothek sein. also müssen wir nur tun.ToDictionary(o=>o.PropertyName)
Jaider
3
@Jaider, gibt es bereits eine solche Funktionalität: ersetzen Sie einfach ToDictionarymit ToLookup.
Robert Synoradzki
19

Ich kann @Michael Blackburn nicht kommentieren, aber ich denke, Sie haben die Ablehnung erhalten, da der GroupBy in diesem Fall nicht erforderlich ist.

Verwenden Sie es wie:

var lookupOfCustomObjects = listOfCustomObjects.ToLookup(o=>o.PropertyName);
var listWithAllCustomObjectsWithPropertyName = lookupOfCustomObjects[propertyName]

Außerdem habe ich gesehen, dass dies viel besser funktioniert als bei Verwendung von GroupBy (). ToDictionary ().

RuudvK
quelle
Ich führte eine Transliteration durch und beantwortete die Frage nicht bestmöglich.
Michael Blackburn
1

Für @ atari2600 würde die Antwort so aussehen, wenn ToLookup in Lambda-Syntax verwendet wird:

var x = listOfCustomObjects
    .GroupBy(o => o.PropertyName)
    .ToLookup(customObject => customObject);

Grundsätzlich nimmt es die IGrouping und materialisiert sie für Sie in einem Listenwörterbuch mit den Werten von PropertyName als Schlüssel.

Michael Blackburn
quelle
Warum eine Ablehnung? Ist das nicht richtig / beantwortet die Frage?
Michael Blackburn
1
Falls Sie es verpasst haben, erwähnte @RuudvK in seiner Antwort, dass er den Verdacht hat, dass die Abwertung darauf zurückzuführen ist, dass GroupBy nicht erforderlich ist. ToLookuphat eine Überlastung, die die Arbeit erledigt.
Jeff B
Ich habe diese Antwort verpasst, danke, dass du mich markiert hast. Sinnvoll, die Gruppierung ist syntaktisch unnötig, ich habe sie nur belassen, um den Übergang von der Abfragesyntax zur Methodensyntax klarer zu gestalten.
Michael Blackburn
GroupBy (die Überladung mit nur einem Parameter) gibt eine IEnumerable <IGrouping <TKey, TSource >> zurück. Das nachfolgende ToLookup verwandelt es dann in einen ziemlich komplizierten Typ, der nicht einmal einem IDictionary <TKey, IList <TSource>> nur dem ToLookup ähnelt gibt den richtigen Typ zurück.
xtofs
-1

Folgendes hat bei mir funktioniert.

var temp = ctx.Set<DbTable>()
  .GroupBy(g => new { g.id })
  .ToDictionary(d => d.Key.id);
Leo Barbas
quelle