Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/linq/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用(单个)LINQ查询计算与组中上一项的差异_C#_Linq - Fatal编程技术网

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