Utwórz słownik na liście z grupowaniem

106

Na liście mam następujący obiekt:

public class DemoClass
{
    public int GroupKey { get; set; }
    public string DemoString { get; set; }
    public object SomeOtherProperty { get; set; }
}

Teraz chcę z tego utworzyć następujący słownik:

Dictionary<int, List<DemoClass>>

Chcę pogrupować List<DemoClass>według nieruchomości GroupKey, ale nie rozumiem, jak to się robi i jakiejś pomocy.

Po zastanowieniu osiągnąłem wymagane zachowanie dzięki:

var groupedDemoClasses = from demoClass in mySepcialVariableWhichIsAListOfDemoClass
                            group demoClass by demoClass.GroupKey
                            into groupedDemoClass
                            select groupedDemoClass;
var neededDictionary = groupedDemoClass.ToDictionary(gdc => gdc.Key, gdc => gdc.ToList());

ale czy istnieje sposób, aby uczynić to jednym stwierdzeniem?

Andreas Niedermair
źródło

Odpowiedzi:

88
var groupedDemoClasses = (from demoClass in mySepcialVariableWhichIsAListOfDemoClass
                          group demoClass by demoClass.GroupKey
                          into groupedDemoClass
                          select groupedDemoClass).ToDictionary(gdc => gdc.Key, gdc => gdc.ToList());

Ten zadziała !!!

Prashant Cholachagudda
źródło
198

Wystarczy, aby sugestia mquander na beton:

var groupedDemoClasses = mySpecialVariableWhichIsAListOfDemoClass
                             .GroupBy(x => x.GroupKey)
                             .ToDictionary(gdc => gdc.Key, gdc => gdc.ToList());

Oczywiście skróciłbyś go, gdybyś użył również krótszych nazw zmiennych :)

Czy mogę jednak zasugerować, że Lookup może być bardziej odpowiedni? Lookup to w zasadzie słownik od klucza do an IEnumerable<T>- chyba że naprawdę potrzebujesz wartości jako listy, sprawia, że ​​kod jest jeszcze krótszy (i bardziej wydajny) dzięki wywołaniu ToLookup :

var groupedDemoClasses = mySpecialVariableWhichIsAListOfDemoClass
                             .ToLookup(x => x.GroupKey);
Jon Skeet
źródło
1
Pomyślałem, że wyszukiwanie nie działa tak dobrze w porównaniu ze słownikiem zbudowanym w środowisku długoterminowym, ponieważ generuje wyniki na bieżąco dla każdego żądania ... popraw mnie, jeśli się mylę!
Andreas Niedermair
Nie, tworzy całe wyszukiwanie. Ogólnie ToXXX nie używa odroczonego wykonania.
Jon Skeet
1
(Możesz myśleć o zgrupowaniu, które jest rzeczywiście odroczone.)
Jon Skeet
1
Gdybym nie był taki złośliwy, zagłosowałbym na ciebie. Przybyłem po Linq, pozostałem po strukturze danych, o której nigdy nie słyszałem!
Chris McCall,
2
@sasikt: Model jest taki, że możesz wyszukać wszystko , a jeśli klucz nie istnieje, otrzymujesz po prostu pustą kolekcję. Jest to często bardziej przydatne niż podejście TryGetValue, IMO.
Jon Skeet,
6

Już uczyniłeś to jednym liniowcem. Po prostu umieść ToDictionaryna końcu swojej pierwszej linii. Jeśli chcesz, aby był krótszy, użyj składni kompozycji funkcjonalnej zamiast składni zapytania.

mqp
źródło
3

Idę trochę off topic tutaj, ale mam do tego wątku becausde szukałem sposobu na stworzenie słownika słownika w LINQ, a rozmowa tutaj prowadzi mnie do odpowiedzi ...

Państwo może używać LINQ do tworzenia słowników wielopoziomowych, co jest przydatne w scenariuszach, gdzie masz więcej niż 1 klucz lub wymiar, który chcesz wyszukać przez. Sztuczka polega na utworzeniu grupy, a następnie przekonwertowaniu jej na słownik w następujący sposób:

  Dim qry = (From acs In ActualSales _
             Group By acs.ProductID Into Group _
             Select ProductID, Months = Group.ToDictionary(Function(c) c.Period) _
            ).ToDictionary(Function(c) c.ProductID)

Wynikowego zapytania można użyć w następujący sposób:

 If qry.ContainsKey(_ProductID) Then
      With qry(_ProductID)
          If .Months.ContainsKey(_Period) Then
             ...
          End If
      End With
 End If

Mam nadzieję, że jest to pomocne dla każdego, kto potrzebuje tego rodzaju zapytania.

znak
źródło