How to rewrite several independent LINQ queries in

2019-06-10 16:40发布

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

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

3条回答
叛逆
2楼-- · 2019-06-10 16:53

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.

查看更多
疯言疯语
3楼-- · 2019-06-10 17:03
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.

查看更多
爷的心禁止访问
4楼-- · 2019-06-10 17:13

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.

查看更多
登录 后发表回答