开发者

How to rewrite several independent LINQ queries into single one using Aggregate()?

I have next very non-optimized code:

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.Expen开发者_如何学编程ditureBank = 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;
}

How to rewrite such it using IEnumerable.Aggregate(), if applicable?


Sometimes a good old fashioned foreach loop is the best tool for the job. I think that's the case here otherwise you're either going to be enumerating the sections multiple times or have some very unreadable LINQ code.

And although you probably know ahead of time that the sections parameter will be an array or collection or what not, it might be something that is very expensive to enumerate or something that doesn't yield consistent values between enumerations. IEnumerable can surprise you sometimes.


my solution is very close to Codesleuth's but would first define a Summary Struct

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

Note that the struct would ideally be immutable.


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

How's that?

EDIT:

Ok, I've had a rethink, take a look:

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

Beware of errors if sections is empty.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜