LINQ Group By w obiekcie słownika


161

Próbuję użyć LINQ, aby utworzyć Dictionary<string, List<CustomObject>>z List<CustomObject>. Mogę to uruchomić używając "var", ale nie chcę używać typów anonimowych. Oto co mam

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

Kiedyś próbowałem również użyć Cast<>()z biblioteki LINQ x, ale pojawiają się problemy z kompilacją, które powodują, że jest to nieprawidłowe rzutowanie.


Co jeśli spróbujesz var x = (z CustomObject o w grupie ListOfCustomObjects o przez o.PropertyName do t select t) .ToList ();
— esastincy

44
Czy jest jakiś powód, dla którego musisz to zrobić, zamiast używać ToLookup, który jest przeznaczony do tego?
— Jon Skeet

1
Jon, czy mógłbyś opublikować przykład, jak działa ToLookup w tej sytuacji? Nie znam tej metody LINQ.
— Atari2600

8
@JonSkeet Jesteś niesamowity! (To znaczy, wszyscy już to wiedzieli, ale nadal.) Powodem, dla którego nie planowałem używać ToLookup, było to, że nigdy o tym nie słyszałem, aż do teraz. Teraz wiem!
— neminem

1
Dla zachowania kompletności, używanie varnie jest typem „anonimowym”, lecz typem „niejawnym”. Typy anonimowe to nowe klasy utworzone przez kompilator do obsługi konstrukcji new { thing = "stuff" };. Typy niejawne są istniejącymi klasami, varsą po prostu wygodnym sposobem na odwołanie się do nich, gdy zmienna jest przypisywana natychmiastowo, typ zmiennej można wywnioskować z typu przypisywanego do niej obiektu. Możesz nawet niejawnie wpisać zmienną odwołującą się do typu anonimowego, np .:var a = new { thing = "stuff" };
— Michael Blackburn

Odpowiedzi:


351
Dictionary<string, List<CustomObject>> myDictionary = ListOfCustomObjects
    .GroupBy(o => o.PropertyName)
    .ToDictionary(g => g.Key, g => g.ToList());

6
Jeśli nie potrzebujesz właściwości z 'CustomObject' jako wartości listy (nie pokazanej w tej odpowiedzi), warto sprawdzić jego kodowość komentarz Jona Skeeta do pytania polecającego ToLookup ().
— Shaun

3
jest to sposób na zrobienie tego, jeśli pożądany jest niezmienny wynik. ToLookup jest niezmienna.
— Amit

1
Moje 2 centy (tylko dlatego, że walczyłem przez godzinę :)): podczas grupowania według nieruchomości upewnij się, że właściwość MA wartość! W przeciwnym razie metoda Todict nie generuje klucza (dla właściwości String przynajmniej ...) :)
— dba

.GroupBy(o => o.PropertyName).ToDictionary(g => g.Key, g => g.ToList())Może to być część rozszerzenia biblioteki Linq. więc musimy tylko zrobić.ToDictionary(o=>o.PropertyName)
— Jaider

3
@Jaider istnieje już taka funkcjonalność: po prostu zastąpić ToDictionaryz ToLookup.
— Robert Synoradzki

19

Nie mogę komentować @Michael Blackburn, ale myślę, że dostałeś głos przeciw, ponieważ GroupBy nie jest w tym przypadku konieczne.

Używaj go jak:

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

Dodatkowo widziałem, że to działa o wiele lepiej niż przy użyciu GroupBy () .ToDictionary ().


Wykonałem transliterację, nie odpowiadając na pytanie w najlepszy możliwy sposób.
— Michael Blackburn

1

Dla @ atari2600 odpowiedź wyglądałaby tak, jak przy użyciu ToLookup w składni lambda:

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

Zasadniczo pobiera IGrouping i materializuje go dla Ciebie w słowniku list, z wartościami PropertyName jako kluczem.


Dlaczego głos przeciw? Czy to nie jest dokładne / nie odpowiada na pytanie?
— Michael Blackburn

1
Na wypadek, gdybyś to przegapił, @RuudvK wspomniał w swojej odpowiedzi , że podejrzewa, że ​​głos przeciwny wynika z tego, że GroupBy jest niepotrzebne. ToLookupma przeciążenie, które wykona zadanie.
— Jeff B

Brakowało mi tej odpowiedzi, dzięki za oznaczenie mnie. Ma sens, ponieważ grupowanie jest składniowo niepotrzebne, zostawiłem je tylko po to, aby przejście od składni zapytania do składni metody było jaśniejsze.
— Michael Blackburn

GroupBy (przeciążenie z tylko jednym parametrem) zwraca IEnumerable <IGrouping <TKey, TSource >>, a następnie ToLookup przekształca go w dość skomplikowany typ, który nie jest nawet podobny do IDictionary <TKey, IList <TSource>> tylko ToLookup zwraca właściwy typ.
— xtofs

-1

Poniższe zadziałały dla mnie.

var temp = ctx.Set<DbTable>()
  .GroupBy(g => new { g.id })
  .ToDictionary(d => d.Key.id);
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.