Подтвердить что ты не робот

Как использовать LINQ, чтобы найти сумму?

У меня есть эта структура:

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

: Firmware (string): key: Device (string): значение CountOfUsers (int)

Мне нужно получить общее количество пользователей для каждого устройства, но я действительно не знаю, как это сделать с LINQ. Уже пробовал много вариантов. Пожалуйста, помогите!

В настоящее время я просто использую для него целую функцию

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;
    }
4b9b3361

Ответ 1

Что-то вроде этого, например?

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

Ответ 2

Поскольку ключи для данных, которые вы хотите скопировать, находятся в словаре второго уровня, хорошим первым шагом было бы сбросить все пары ключевого значения из внутренних словарей в плоскую последовательность. После этого все, что вам нужно, это агрегировать подсчеты, например:

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

Ответ 3

Словарь реализует IEnumerable<KeyValuePair<TKey,TValue>, что означает, что вы можете использовать LINQ на нем. В этом случае у вас есть словарь словарей и вам нужно группировать ключ второго уровня. Для этого вам нужно сгладить словари, что можно сделать с помощью SelectMany

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

Как только у вас есть записи на уровне листа, вы можете группировать их по клавишам:

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

И вычислить сумму для каждой группы:

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

Эквивалентный запрос довольно чист:

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)
                         };

Учитывая следующий словарь:

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
                }                    
};

Оба запроса возвращают те же значения

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

Ответ 4

Вы можете сделать это следующим образом:

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));
Результат

будет выглядеть следующим образом: введите описание изображения здесь