2016-12-21 21 views
25

mam tę strukturę:Jak korzystać z LINQ, aby znaleźć kwotę?

private readonly Dictionary<string, Dictionary<string, int>> _storage = 
    new Dictionary<string, Dictionary<string, int>>(); 

klucz: Firmware (string): Klucz: Device (String): CountOfUsers wartości (int)

muszę się całkowitej użytkowników dla każdego urządzenia, ale Naprawdę nie wiem jak to zrobić z LINQ. Wypróbowałem już wiele wariantów. Proszę pomóż!

Na razie wystarczy użyć całą funkcję dla niego

private XlsRow2 GetTotalPerDevice(Dictionary<string, Dictionary<string, int>> storage) 
    { 
     XlsRow2 totalPerDeviceRow = new XlsRow2(); 
     totalPerDeviceRow._Name = "Grand Total"; 
     totalPerDeviceRow.UseBorders = true; 
     foreach (var deviceModel in _allDeviceModels) 
     { 
      foreach (var firmware in storage) 
      { 
       foreach (var device in firmware.Value) 
       { 
        var countOfUsers = 0; 
        if (deviceModel == device.Key) 
        { 
         countOfUsers += device.Value; 

         if (!_totalsPerDevice.ContainsKey(deviceModel)) 
         { 
          _totalsPerDevice.Add(deviceModel, countOfUsers); 
         } 
         else 
         { 
          _totalsPerDevice[deviceModel] += countOfUsers; 
         } 
        } 
       } 
      } 
     } 
     foreach (var deviceModel in _allDeviceModels) 
     { 
      if (_totalsPerDevice.ContainsKey(deviceModel)) 
      { 
       totalPerDeviceRow._AddColumn(_totalsPerDevice.First(k => k.Key == deviceModel.ToString()).Value.ToString()); 
      } 
      else 
      { 
       totalPerDeviceRow._AddColumn(""); 
      } 
     } 
     return totalPerDeviceRow; 
    } 

Odpowiedz

31

coś takiego na przykład?

var result = _storage.SelectMany(x => x.Value) 
    .GroupBy(x => x.Key) 
    .Select(x => new { Device = x.Key, Total = x.Sum(y => y.Value) }); 
11

Od kluczy do danych, które chcesz zsumować ma w słowniku drugiego poziomu, dobrym pierwszym krokiem byłoby zrzucić wszystkie pary klucz-wartość z wewnętrznych słowników na płaskiej sekwencji. Po tym wszystkim, co potrzebne jest do agregowania liczniki, tak:

var res = _storage 
    .SelectMany(d => d.Value) 
    .GroupBy(kvp => kvp.Key) 
    .ToDictionary(g => g.Key, g => g.Sum(kvp => kvp.Value)); 
+0

Jeszcze raz rada, która nie zawsze najlepsza odpowiedź, ma najwyższy wynik, ale po prostu ten, który ma już wiele głosów. Przepraszam. brachu. – HimBromBeere

10

A Dictionary realizuje IEnumerable<KeyValuePair<TKey,TValue> który oznacza, że ​​można używać LINQ na nim. W tym przypadku masz słownik słowników i musisz grupować według klucza drugiego poziomu. Aby to zrobić, trzeba spłaszczyć słowniki, coś, co można zrobić z SelectMany

_storage.Selectmany(pair=>pair.Value); 

Gdy masz wpisy liść poziomu, można grupować według ich klucze:

_storage.Selectmany(pair=>pair.Value) 
     .GroupBy(leaf=>leaf.Key); 

i obliczyć suma z każdej grupy:

var totals=_storage.SelectMany(pair=>pair.Value) 
        .GroupBy(leaf=>leaf.Key) 
        .Select(grp=>new { 
             Device = grp.Key, 
             TotalUsers =grp.Sum(leaf=>leaf.Value) 
            }); 

równoważnik zapytanie jest raczej czyszczenia:

var totals2 = from frm in _storage 
       from dev in frm.Value 
       group dev by dev.Key into grp 
       select new { 
          Device = grp.Key, 
          Total=grp.Sum(leaf=>leaf.Value) 
         }; 

Biorąc pod uwagę następujące słownika:

var _storage = new Dictionary<string, Dictionary<string, int>> { 
    ["Frm1"]=new Dictionary<string, int> { 
        ["Device1"]=4, 
        ["Device2"]=5 
       }, 
    ["Frm2"]=new Dictionary<string, int> { 
        ["Device1"]=41, 
        ["Device3"]=5 
       }      
}; 

obu zapytań zwraca te same wartości

foreach(var total in totals) 
{ 
    Console.WriteLine ($"{total.Device} = {total.Total}"); 
} 
------------------ 
Device1 = 45 
Device2 = 5 
Device3 = 5 
5

Można to zrobić tak:

Dictionary<string, Dictionary<string, int>> _storage = new Dictionary<string, Dictionary<string, int>>(); 
Dictionary<string, int> x = new Dictionary<string, int>(); 
x.Add("x", 2); 
x.Add("z", 2); 
x.Add("y", 2); 
_storage.Add("x", x); 
_storage.Add("z", x); 
_storage.Add("y", x); 

var b = _storage.SelectMany(keyValuePair => keyValuePair.Value) 
     .GroupBy(keyValuePair => keyValuePair.Key) 
     .ToDictionary(valuePairs => valuePairs.Key, grouping => grouping.Sum(kvp => kvp.Value)); 

rezultat będzie podobny: enter image description here