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

Несколько СУММ с помощью LINQ

У меня есть цикл вроде следующего: могу ли я сделать то же самое с помощью нескольких SUM?

foreach (var detail in ArticleLedgerEntries.Where(pd => pd.LedgerEntryType == LedgerEntryTypeTypes.Unload &&
                                                                pd.InventoryType == InventoryTypes.Finished))
{
     weight += detail.GrossWeight;
     length += detail.Length;
     items  += detail.NrDistaff;
}
4b9b3361

Ответ 1

Технически говоря, то, что у вас есть, - это, пожалуй, самый эффективный способ сделать то, что вы просите. Однако вы можете создать метод расширения в IEnumerable <T> Каждый может сделать это проще:

public static class EnumerableExtensions
{
    public static void Each<T>(this IEnumerable<T> col, Action<T> itemWorker)
    {
        foreach (var item in col)
        {
            itemWorker(item);
        }
    }
}

И назовите его так:

// Declare variables in parent scope
double weight;
double length;
int items;

ArticleLedgerEntries
    .Where(
        pd => 
           pd.LedgerEntryType == LedgerEntryTypeTypes.Unload &&
           pd.InventoryType == InventoryTypes.Finished
    )
    .Each(
        pd => 
        {
            // Close around variables defined in parent scope
            weight += pd.GrossWeight; 
            lenght += pd.Length;
            items += pd.NrDistaff;
        }
    );

UPDATE: Еще одно примечание. Вышеприведенный пример основан на закрытии. Вес переменных, длина и элементы должны быть объявлены в родительской области, что позволяет им оставаться за каждым вызовом к действию itemWorker. Я обновил этот пример, чтобы отразить это ради ясности.

Ответ 2

Вы можете вызвать Sum три раза, но он будет медленнее, потому что он сделает три цикла.

Например:

var list = ArticleLedgerEntries.Where(pd => pd.LedgerEntryType == LedgerEntryTypeTypes.Unload
                                   && pd.InventoryType == InventoryTypes.Finished))

var totalWeight = list.Sum(pd => pd.GrossWeight);
var totalLength = list.Sum(pd => pd.Length);
var items = list.Sum(pd => pd.NrDistaff); 

В связи с задержкой выполнения, он также будет повторно оценивать вызов Where каждый раз, хотя это не проблема в вашем случае. Этого можно избежать, вызвав ToArray, но это вызовет распределение массива. (И он все равно будет запускать три цикла)

Однако, если у вас не очень большое количество записей или этот код работает в узком цикле, вам не нужно беспокоиться о производительности.


EDIT. Если вы действительно хотите использовать LINQ, вы можете неправильно использовать Aggregate, например:

int totalWeight, totalLength, items;

list.Aggregate((a, b) => { 
    weight += detail.GrossWeight;
    length += detail.Length;
    items  += detail.NrDistaff;
    return a;
});

Это феноменально уродливый код, но он должен выполняться почти так же, как прямой цикл.

Вы также можете суммировать в аккумуляторе (см. пример ниже), но это будет выделять временный объект для каждого элемента в вашем списке, что является немой идеей. (Анонимные типы неизменяемы)

var totals = list.Aggregate(
    new { Weight = 0, Length = 0, Items = 0},
    (t, pd) => new { 
        Weight = t.Weight + pd.GrossWeight,
        Length = t.Length + pd.Length,
        Items = t.Items + pd.NrDistaff
    }
);

Ответ 3

Вы также можете группировать true - 1 (который фактически включает любой из элементов, а затем их подсчитывать или летать):

 var results = from x in ArticleLedgerEntries
                       group x by 1
                       into aggregatedTable
                       select new
                                  {
                                      SumOfWeight = aggregatedTable.Sum(y => y.weight),
                                      SumOfLength = aggregatedTable.Sum(y => y.Length),
                                      SumOfNrDistaff = aggregatedTable.Sum(y => y.NrDistaff)
                                  };

Что касается времени выполнения, он почти так же хорош, как и цикл (с постоянным добавлением).

Ответ 5

Ok. Я понимаю, что нет простого способа сделать это с помощью LINQ. Я возьму цикл foreach, потому что понял, что это не так плохо. Спасибо всем вам.