Как переписать несколько независимых запросов LINQ в один, используя Aggregate ()? - PullRequest
0 голосов
/ 26 января 2010

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

void Summarize(IEnumerable<Section> sections)
{
    this.DateBegin = sections.Select(s => s.Date).Min();
    this.DateEnd = sections.Select(s => s.Date).Max();
    this.Income = sections.Where(s => s.IsIncome).Sum(r => r.Amount);
    this.ExpenditureBank = sections.Where(s => s.IsExpenditureBank).Sum(r => r.Amount);
    this.ExpenditureClient = sections.Where(s => s.IsExpenditureClient).Sum(r => r.Amount);
    this.Expenditure = this.ExpenditureBank + this.ExpenditureClient;
}

Как переписать такое с помощью IEnumerable.Aggregate(), если применимо?

Ответы [ 3 ]

4 голосов
/ 26 января 2010

Иногда старый добрый цикл foreach - лучший инструмент для работы. Я думаю, что это так, иначе вы либо будете перечислять разделы несколько раз, либо у вас будет какой-то очень нечитаемый код LINQ.

И хотя вы, вероятно, заранее знаете, что параметр section будет массивом или коллекцией или что-то еще, это может быть что-то очень дорогостоящее для перечисления или что-то, что не дает согласованных значений между перечислениями. IEnumerable иногда может вас удивить.

1 голос
/ 26 января 2010

мое решение очень близко к Colesleuth, но сначала определит итоговую структуру

struct Summary 
{
    public DateTime DateBegin {get; set;}
    public DateTime DateEnd {get; set;}
    public int Income  {get; set;}
    public int ExpenditureBank {get; set;}
    public int ExpenditureClient {get; set;}
    public int Expenditure {get {return ExpenditureBank+ExpenditureClient; }}
}

void Summarize(IEnumerable<Section> sections)
{
    var result = sections.Aggregate(new Summary
    {
        DateBegin = DateTime.MaxValue,
        DateEnd = DateTime.MinValue,
        Income = 0,
        ExpenditureBank =0,
        ExpenditureClient =0,
    },
    (agg, next) =>
    new Summary
    {
        DateBegin = next.Date < agg.DateBegin ? next.Date : agg.DateBegin,
        DateEnd = next.Date > agg.DateEnd ? next.Date : agg.DateEnd,
        Income = agg.Income + (next.IsIncome ? next.Amount : 0),
        ExpenditureBank = next.IsExpenditureBank ? next.Amount: 0,
        ExpenditureClient = next.IsExpenditureClient ? next.Amount : 0
    });
}

Обратите внимание, что структура в идеале должна быть неизменной.

1 голос
/ 26 января 2010
void Summarize(IEnumerable<Section> sections)
{
    this.DateBegin = sections.Select(s => s.Date).Min();
    this.DateEnd = sections.Select(s => s.Date).Max();
    this.Income = sections.Where(s => s.IsIncome).Sum(r => r.Amount);
    this.Expenditure = sections.Aggregate(0, (agg, next) => 
        agg += (next.IsExpenditureBank ? next.Amount : 0) +
            (next.IsExpenditureClient ? next.Amount : 0));
}

Как это?

EDIT:

Хорошо, я переосмыслил, посмотрите:

void Summarize(IEnumerable<Section> sections)
{
    var result = sections.Aggregate(new
    {
        DateBegin = DateTime.MaxValue,
        DateEnd = DateTime.MinValue,
        Income = 0,
        Expenditure = 0
    },
        (agg, next) =>
        new
        {
            DateBegin = next.Date < agg.DateBegin ? next.Date : agg.DateBegin,
            DateEnd = next.Date > agg.DateEnd ? next.Date : agg.DateEnd,
            Income = agg.Income + (next.IsIncome ? next.Amount : 0),
            Expenditure = agg.Expenditure + (next.IsExpenditureBank ? next.Amount : 0) +
                (next.IsExpenditureClient ? next.Amount : 0)
        }
    );
}

Остерегайтесь ошибок, если sections пусто.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...