繁体   English   中英

如何对分组记录执行操作?

[英]How to perform operation on grouped records?

这是我的记录:

Id    EmpName        Stats
  1      Abc            1000  
  1      Abc            3000
  1      Abc            2000
  2      Pqr            4000
  2      Pqr            5000  
  2      Pqr            6000
  2      Pqr            7000

我正在尝试对ID字段进行分组,并且在按分组进行分组后,我想要这样的输出:

预期产量

Id   EmpName     Stats
1     Abc        3000
2     Pqr        3000

对于第一个输出记录的计算是这样的:

3000 - 1000=2000  (i.e subtract highest - lowest from 1st and 2nd records)
3000 - 2000=1000  (i.e subtract highest - lowest from 2nd and 3rd records)

Total=2000 + 1000 =3000


For 2nd output record calculation is like this:
5000 - 4000=1000  (i.e subtract highest - lowest from first two records)
6000 - 5000=1000  
7000 - 6000=1000
total=1000 + 1000=2000

这是我创建的1个样本小提琴: 小提琴

到目前为止,我已经设法按ID对记录进行分组,但是现在如何对组记录执行此计算?

首先,就像我的评论中提到的那样,可以使用单个linq查询来完成此操作,但是会带来很多复杂性,其中一个就是无法读取的代码。

使用IGrouping列表上的简单foreach

更新(处理动态组长度):

var list = CreateData();
var groupList = list.GroupBy(t => t.Id);

var finalList = new List<Employee>();

//Iterate on the groups
foreach(var grp in groupList){
    var part1 = grp.Count()/2;
    var part2 = (int)Math.Ceiling((double)grp.Count()/2);
    var firstSet = grp.Select(i=>i.Stats).Take(part2);
    var secondSet = grp.Select(i=>i.Stats).Skip(part1).Take(part2);
    var total = (firstSet.Max() - firstSet.Min()) + (secondSet.Max() - secondSet.Min());
    finalList.Add(new Employee{
        Id = grp.Key,
        EmpName = grp.FirstOrDefault().EmpName,
        Stats = total
    });

}   

*注意 -

您可以优化用于获取数据进行计算的逻辑。

更为复杂的逻辑是在不固定的情况下将组划分为相等的部分。

更新小提琴


LinQ方式

var list = CreateData();
var groupList = list.GroupBy(t => t.Id);
var testLinq = (from l in list
                group l by l.Id into grp
                let part1 = grp.Count()/2
                let part2 = (int)Math.Ceiling((double)grp.Count()/2)
                let firstSet = grp.Select(i=>i.Stats).Take(part2)
                let secondSet = grp.Select(i=>i.Stats).Skip(part1).Take(part2)
                select new Employee{
                    Id = grp.Key,
                    EmpName = grp.FirstOrDefault().EmpName,
                    Stats = (firstSet.Max() - firstSet.Min()) + (secondSet.Max() - secondSet.Min())
                }).ToList();

您可以使用Aggregate方法重载,该重载允许您维护自定义累加器状态。

对于您而言,我们将维护以下内容:

decimal Sum; // Current result
decimal Prev; // Previous element Stats (zero for the first element)
int Index; // The index of the current element

基本上只需要使用Index来避免将第一个元素Stats累积到结果中。

这是查询:

var result = list.GroupBy(t => t.Id)
    .Select(g => new
    {
        ID = g.Key,
        Name = g.First().EmpName,
        Stats = g.Aggregate(
            new { Sum = 0m, Prev = 0m, Index = 0 },
            (a, e) => new
            {
                Sum = (a.Index < 2 ? 0 : a.Sum) + Math.Abs(e.Stats - a.Prev),
                Prev = e.Stats,
                Index = a.Index + 1
            }, a => a.Sum)
    }).ToList();

编辑:根据注释中的要求,这是上述Aggregate用法的foreach等效项:

static decimal GetStats(IEnumerable<Employee> g)
{
    decimal sum = 0;
    decimal prev = 0;
    int index = 0;
    foreach (var e in g)
    {
        sum = (index < 2 ? 0 : sum) + Math.Abs(e.Stats - prev);
        prev = e.Stats;
        index++;        
    }
    return sum;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM