[英]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.