在groupby和selectmany之后使用linq保留订单

时间:2016-03-10 01:40:20

标签: c# linq

有没有办法在这个linq表达式后保留顺序?

var results =
  DateList
    .GroupBy(x => x.Date.Subtract(firstDay).Days / 7 + 1)
     .SelectMany(gx => gx, (gx, x) => new {Week =  gx.Key,DateTime =x,Count = gx.Count(),});

我发现了这个Preserving order with LINQ,但我不确定它的GroupBy或SelectMany是否存在问题

2 个答案:

答案 0 :(得分:2)

是的,如果您首先选择DateList并将其与索引合并,则使用overload of .Select使用带有第二个(int)参数的委托,该参数使用来自中的项目的索引进行调用顺序:

DateList
    .Select((dateTime, idx) => new {dateTime, idx})
    .GroupBy(x => x.dateTime.Date.Subtract(firstDay).Days / 7 + 1)

...并通过linq链保持价值

    .SelectMany(gx => gx, (gx, x) => new {Week =  gx.Key,
                                          DateTime = x.dateTime, 
                                          Count = gx.Count(), 
                                          x.idx})

...然后用它来重新排序输出

    .OrderBy(x => x.idx)

...并从最终选择中删除

    .Select(x => new {x.Week, x.DateTime, x.Count});

然后您可以保持与原始列表相同的顺序。

答案 1 :(得分:0)

@spender的解决方案很好,但可以在没有OrderBy的情况下完成吗?它可以,因为我们可以使用索引直接索引到数组中,但它不会是一个linq查询:

var resultsTmp =
    DateList.Select((d, i) => new { d, i })
    .GroupBy(x => x.d.Date.Subtract(firstDay).Days / 7 + 1)
    .SelectMany(gx => gx, (gx, x) => new { Week = gx.Key, DateTime = x.d, Count = gx.Count(), x.i })
    .ToArray();

var resultsTmp2 = resultsTmp.ToArray();
foreach (var r in resultsTmp) { resultsTmp2[r.i] = r; };
var results = resultsTmp2.Select(r => new { r.Week, r.DateTime, r.Count });

看起来有点复杂。我可能会做更直接的事情,如:

var DateList2 = DateList.Select(d => new { DateTime = d, Week = d.Subtract(firstDay).Days / 7 + 1 }).ToArray();
var weeks = DateList2.GroupBy(d => d.Week).ToDictionary(k => k.Key, v => v.Count());
var results = DateList2.Select(d2 => new { d2.Week, d2.DateTime, Count = weeks[d2.Week] });