C# 使用(单个)LINQ查询计算与组中上一项的差异
当数据需要分组时,我试图找出如何计算与前一项的差异 我有这样的数据C# 使用(单个)LINQ查询计算与组中上一项的差异,c#,linq,C#,Linq,当数据需要分组时,我试图找出如何计算与前一项的差异 我有这样的数据 City Area Date Citizens New York 1 2010.11.20 5 New York 1 2010.11.21 8 New York 1 2010.11.22 12 New York 1 2010.11.23 17 New York 1 2010.11.24 23 New York 1 2010.11.25
City Area Date Citizens
New York 1 2010.11.20 5
New York 1 2010.11.21 8
New York 1 2010.11.22 12
New York 1 2010.11.23 17
New York 1 2010.11.24 23
New York 1 2010.11.25 29
Chicago 1 2010.11.20 5
Chicago 1 2010.11.21 10
Chicago 1 2010.11.22 15
Chicago 1 2010.11.23 20
Chicago 1 2010.11.24 25
Chicago 1 2010.11.25 30
New York 2 2010.11.20 6
New York 2 2010.11.21 7
New York 2 2010.11.22 9
New York 2 2010.11.23 7
New York 2 2010.11.24 10
New York 2 2010.11.25 15
Chicago 2 2010.11.20 5
Chicago 2 2010.11.21 15
Chicago 2 2010.11.22 25
Chicago 2 2010.11.23 20
Chicago 2 2010.11.24 25
Chicago 2 2010.11.25 30
我需要为每个城市的每一个都添加一列“增加”,这将通过从当前的人口中减去以前的公民数量来计算
The expected result is like this
City Area Date Citizens Increase
New York 1 2010.11.20 5 5
New York 1 2010.11.21 8 3
New York 1 2010.11.22 12 4
New York 1 2010.11.23 17 5
New York 1 2010.11.24 23 6
New York 1 2010.11.25 29 7
Chicago 1 2010.11.20 5 5
Chicago 1 2010.11.21 10 5
Chicago 1 2010.11.22 15 5
Chicago 1 2010.11.23 20 5
Chicago 1 2010.11.24 25 5
Chicago 1 2010.11.25 30 5
New York 2 2010.11.20 6 6
New York 2 2010.11.21 7 1
New York 2 2010.11.22 9 2
New York 2 2010.11.23 7 -2
New York 2 2010.11.24 10 3
New York 2 2010.11.25 15 5
Chicago 2 2010.11.20 5 5
Chicago 2 2010.11.21 15 10
Chicago 2 2010.11.22 25 10
Chicago 2 2010.11.23 20 -5
Chicago 2 2010.11.24 25 5
Chicago 2 2010.11.25 30 5
我想知道这是否可以通过一个linq查询来完成,避免
“foreach(城市中的c)
foreach(区域中的a)
……”
问题是如何计算行“7”,其中与上一条记录的差值为-24,而is应为5
下面是一个示例代码:
using System;
using System.Collections.Generic;
namespace ConsoleApplication1
{
public class MyObject
{
public int ID { get; set; }
public string City { get;set; }
public DateTime Date { get; set; }
public int Value { get; set; }
public int DiffToPrev { get; set; }
}
class Program
{
static void Main()
{
var list = new List<MyObject>
{
new MyObject {ID= 1, City = "New York",Date = DateTime.Now, Value = 5},
new MyObject {ID= 1, City = "New York",Date = DateTime.Now.AddDays(1),Value = 8},
new MyObject {ID= 1, City = "New York",Date = DateTime.Now.AddDays(2),Value = 12},
new MyObject {ID= 1, City = "New York",Date = DateTime.Now.AddDays(3),Value = 17},
new MyObject {ID= 1, City = "New York",Date = DateTime.Now.AddDays(4),Value = 23},
new MyObject {ID= 1, City = "New York",Date = DateTime.Now.AddDays(5),Value = 29},
new MyObject {ID= 1, City = "Chicago",Date = DateTime.Now, Value = 5},
new MyObject {ID= 1, City = "Chicago",Date = DateTime.Now.AddDays(1),Value = 10},
new MyObject {ID= 1, City = "Chicago",Date = DateTime.Now.AddDays(2),Value = 15},
new MyObject {ID= 1, City = "Chicago",Date = DateTime.Now.AddDays(3),Value = 20},
new MyObject {ID= 1, City = "Chicago",Date = DateTime.Now.AddDays(4),Value = 25},
new MyObject {ID= 1, City = "Chicago",Date = DateTime.Now.AddDays(5),Value = 30},
new MyObject {ID= 2, City = "New York",Date = DateTime.Now, Value = 6},
new MyObject {ID= 2, City = "New York",Date = DateTime.Now.AddDays(1),Value = 7},
new MyObject {ID= 2, City = "New York",Date = DateTime.Now.AddDays(2),Value = 9},
new MyObject {ID= 2, City = "New York",Date = DateTime.Now.AddDays(3),Value = 7},
new MyObject {ID= 2, City = "New York",Date = DateTime.Now.AddDays(4),Value = 10},
new MyObject {ID= 2, City = "New York",Date = DateTime.Now.AddDays(5),Value = 15},
new MyObject {ID= 2, City = "Chicago",Date = DateTime.Now, Value = 5},
new MyObject {ID= 2, City = "Chicago",Date = DateTime.Now.AddDays(1),Value = 15},
new MyObject {ID= 2, City = "Chicago",Date = DateTime.Now.AddDays(2),Value = 25},
new MyObject {ID= 2, City = "Chicago",Date = DateTime.Now.AddDays(3),Value = 20},
new MyObject {ID= 2, City = "Chicago",Date = DateTime.Now.AddDays(4),Value = 25},
new MyObject {ID= 2, City = "Chicago",Date = DateTime.Now.AddDays(5),Value = 30},
};
}
}
}
使用系统;
使用System.Collections.Generic;
命名空间控制台应用程序1
{
公共类MyObject
{
公共int ID{get;set;}
公共字符串City{get;set;}
公共日期时间日期{get;set;}
公共int值{get;set;}
公共int DiffToPrev{get;set;}
}
班级计划
{
静态void Main()
{
变量列表=新列表
{
新的MyObject{ID=1,City=“newyork”,Date=DateTime。现在,Value=5},
newmyObject{ID=1,City=“newyork”,Date=DateTime.Now.AddDays(1),Value=8},
newmyObject{ID=1,City=“newyork”,Date=DateTime.Now.AddDays(2),Value=12},
newmyObject{ID=1,City=“newyork”,Date=DateTime.Now.AddDays(3),Value=17},
new MyObject{ID=1,City=“newyork”,Date=DateTime.Now.AddDays(4),Value=23},
newmyObject{ID=1,City=“newyork”,Date=DateTime.Now.AddDays(5),Value=29},
新的MyObject{ID=1,City=“Chicago”,Date=DateTime。现在,Value=5},
新的MyObject{ID=1,City=“Chicago”,Date=DateTime.Now.AddDays(1),Value=10},
新的MyObject{ID=1,City=“Chicago”,Date=DateTime.Now.AddDays(2),Value=15},
新的MyObject{ID=1,City=“Chicago”,Date=DateTime.Now.AddDays(3),Value=20},
新的MyObject{ID=1,City=“Chicago”,Date=DateTime.Now.AddDays(4),Value=25},
新的MyObject{ID=1,City=“Chicago”,Date=DateTime.Now.AddDays(5),Value=30},
新的MyObject{ID=2,City=“newyork”,Date=DateTime。现在,Value=6},
new MyObject{ID=2,City=“newyork”,Date=DateTime.Now.AddDays(1),Value=7},
newmyObject{ID=2,City=“newyork”,Date=DateTime.Now.AddDays(2),Value=9},
newmyObject{ID=2,City=“newyork”,Date=DateTime.Now.AddDays(3),Value=7},
newmyObject{ID=2,City=“newyork”,Date=DateTime.Now.AddDays(4),Value=10},
new MyObject{ID=2,City=“newyork”,Date=DateTime.Now.AddDays(5),Value=15},
新的MyObject{ID=2,City=“Chicago”,Date=DateTime。现在,Value=5},
新的MyObject{ID=2,City=“Chicago”,Date=DateTime.Now.AddDays(1),Value=15},
新的MyObject{ID=2,City=“Chicago”,Date=DateTime.Now.AddDays(2),Value=25},
新的MyObject{ID=2,City=“Chicago”,Date=DateTime.Now.AddDays(3),Value=20},
新的MyObject{ID=2,City=“Chicago”,Date=DateTime.Now.AddDays(4),Value=25},
新的MyObject{ID=2,City=“Chicago”,Date=DateTime.Now.AddDays(5),Value=30},
};
}
}
}
您可以这样做:
var newList = list.GroupBy(x => new { x.City, x.ID })
.Select
(
x =>
{
var subList = x.OrderBy(y => y.Date).ToList();
return subList.Select((y, idx) => new MyObject
{
ID = y.ID,
City = y.City,
Date = y.Date,
Value = y.Value,
DiffToPrev = (idx == 0) ? y.Value : y.Value - subList.ElementAt(idx-1).Value
});
}
)
.SelectMany(x => x)
.ToList();
无论如何,我认为在这种情况下,foreach语句更清晰(而不是更长),例如: 解决方案使用: 您需要参考
System.Interactive
另一个版本重用您的MyObject
:
var result = list
.GroupBy(o => new { o.City, o.ID })
.SelectMany(g => g
.Zip(zero.Concat(g), (o1, o2) =>
new MyObject {
ID = o1.ID, City = o1.City, Date = o1.Date, Value = o1.Value, DiffToPrev = o1.Value - o2.Value
}));
试试这个:
list.OrderBy (l => l.Date)
.GroupBy (l => new { l.ID, l.City })
.ToList()
.ForEach(g => g.Aggregate (0, (acc, m) => { m.DiffToPrev = m.Value - acc; return m.Value; }));
这里我按日期订购,以防它们过期,然后按ID和城市分组。将其放入列表中,然后对每个组使用聚合函数设置与组中上一个值的差异
您可以在以下内容中看到结果:
已编辑,我将0计算到第一个条目,而不是当前值;)@Martynas这是LINQ,但这些新方法只有在.NET4.0之后才可用。要在早期版本的.NET中使用它们,您可以单独下载库。即使您的代码运行良好,实际上您的LINQ
Aggregate
usage也有点不正常。事实上,你所做的只是一个初始状态的foreach,但更模糊。IMHO在这些情况下(即LINQ有副作用),最好使用循环(或List.ForEach
/ForEach
扩展),因为更清楚它的意图。在我看来,还有一个参数需要考虑。数据实际上存储在SQL server中,并转换为对象(如MS Entity或DevXPress XPO)。在这种情况下,优先考虑将尽可能多的操作移动到SQL server(这意味着SQL server将尽可能进行分组、排序和计数)
var zero = EnumerableEx.Return(new MyObject { Value = 0 });
var result = list
.GroupBy(o => new { o.City, o.ID })
.SelectMany(g => g
.Zip(zero.Concat(g), (o1, o2) =>
new { O = o1, Diff = o1.Value - o2.Value }));
var result = list
.GroupBy(o => new { o.City, o.ID })
.SelectMany(g => g
.Zip(zero.Concat(g), (o1, o2) =>
new MyObject {
ID = o1.ID, City = o1.City, Date = o1.Date, Value = o1.Value, DiffToPrev = o1.Value - o2.Value
}));
list.OrderBy (l => l.Date)
.GroupBy (l => new { l.ID, l.City })
.ToList()
.ForEach(g => g.Aggregate (0, (acc, m) => { m.DiffToPrev = m.Value - acc; return m.Value; }));
ID: 1, City: New York, Date: 11/21/2010 9:01:30 AM, Value: 5, DiffToPrev: 5
ID: 1, City: New York, Date: 11/22/2010 9:01:30 AM, Value: 8, DiffToPrev: 3
ID: 1, City: New York, Date: 11/23/2010 9:01:30 AM, Value: 12, DiffToPrev: 4
ID: 1, City: New York, Date: 11/24/2010 9:01:30 AM, Value: 17, DiffToPrev: 5
ID: 1, City: New York, Date: 11/25/2010 9:01:30 AM, Value: 23, DiffToPrev: 6
ID: 1, City: New York, Date: 11/26/2010 9:01:30 AM, Value: 29, DiffToPrev: 6
ID: 1, City: Chicago, Date: 11/21/2010 9:01:30 AM, Value: 5, DiffToPrev: 5
ID: 1, City: Chicago, Date: 11/22/2010 9:01:30 AM, Value: 10, DiffToPrev: 5
ID: 1, City: Chicago, Date: 11/23/2010 9:01:30 AM, Value: 15, DiffToPrev: 5
ID: 1, City: Chicago, Date: 11/24/2010 9:01:30 AM, Value: 20, DiffToPrev: 5
ID: 1, City: Chicago, Date: 11/25/2010 9:01:30 AM, Value: 25, DiffToPrev: 5
ID: 1, City: Chicago, Date: 11/26/2010 9:01:30 AM, Value: 30, DiffToPrev: 5
ID: 2, City: New York, Date: 11/21/2010 9:01:30 AM, Value: 6, DiffToPrev: 6
ID: 2, City: New York, Date: 11/22/2010 9:01:30 AM, Value: 7, DiffToPrev: 1
ID: 2, City: New York, Date: 11/23/2010 9:01:30 AM, Value: 9, DiffToPrev: 2
ID: 2, City: New York, Date: 11/24/2010 9:01:30 AM, Value: 7, DiffToPrev: -2
ID: 2, City: New York, Date: 11/25/2010 9:01:30 AM, Value: 10, DiffToPrev: 3
ID: 2, City: New York, Date: 11/26/2010 9:01:30 AM, Value: 15, DiffToPrev: 5
ID: 2, City: Chicago, Date: 11/21/2010 9:01:30 AM, Value: 5, DiffToPrev: 5
ID: 2, City: Chicago, Date: 11/22/2010 9:01:30 AM, Value: 15, DiffToPrev: 10
ID: 2, City: Chicago, Date: 11/23/2010 9:01:30 AM, Value: 25, DiffToPrev: 10
ID: 2, City: Chicago, Date: 11/24/2010 9:01:30 AM, Value: 20, DiffToPrev: -5
ID: 2, City: Chicago, Date: 11/25/2010 9:01:30 AM, Value: 25, DiffToPrev: 5
ID: 2, City: Chicago, Date: 11/26/2010 9:01:30 AM, Value: 30, DiffToPrev: 5