我正在尝试使用LINQ为图形准备数据.
我无法解决的问题是如何计算"与以前的差异.
我期望的结果是
ID = 1,Date = Now,DiffToPrev = 0;
ID = 1,日期=现在+ 1,DiffToPrev = 3;
ID = 1,日期=现在+ 2,DiffToPrev = 7;
ID = 1,日期=现在+ 3,DiffToPrev = -6;
等等...
你能帮我创建这样的查询吗?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
public class MyObject
{
public int ID { get; set; }
public DateTime Date { get; set; }
public int Value { get; set; }
}
class Program
{
static void Main()
{
var list = new List<MyObject>
{
new MyObject {ID= 1,Date = DateTime.Now,Value = 5},
new MyObject {ID= 1,Date = DateTime.Now.AddDays(1),Value = 8},
new MyObject {ID= 1,Date = DateTime.Now.AddDays(2),Value = 15},
new MyObject {ID= 1,Date = DateTime.Now.AddDays(3),Value = 9},
new MyObject {ID= 1,Date = DateTime.Now.AddDays(4),Value = 12},
new MyObject {ID= 1,Date = DateTime.Now.AddDays(5),Value = 25},
new MyObject {ID= 2,Date = DateTime.Now,Value = 10},
new MyObject {ID= 2,Date = DateTime.Now.AddDays(1),Value = 7},
new MyObject {ID= 2,Date = DateTime.Now.AddDays(2),Value = 19},
new MyObject {ID= 2,Date = DateTime.Now.AddDays(3),Value = 12},
new MyObject {ID= 2,Date = DateTime.Now.AddDays(4),Value = 15},
new MyObject {ID= 2,Date = DateTime.Now.AddDays(5),Value = 18}
};
Console.WriteLine(list);
Console.ReadLine();
}
}
}
Run Code Online (Sandbox Code Playgroud)
Jon*_*eet 59
一个选项(对于LINQ to Objects)将创建自己的LINQ运算符:
// I don't like this name :(
public static IEnumerable<TResult> SelectWithPrevious<TSource, TResult>
(this IEnumerable<TSource> source,
Func<TSource, TSource, TResult> projection)
{
using (var iterator = source.GetEnumerator())
{
if (!iterator.MoveNext())
{
yield break;
}
TSource previous = iterator.Current;
while (iterator.MoveNext())
{
yield return projection(previous, iterator.Current);
previous = iterator.Current;
}
}
}
Run Code Online (Sandbox Code Playgroud)
这使您可以仅使用源序列的一次传递来执行投影,这总是一个奖励(想象一下在大型日志文件上运行它).
请注意,它会将一系列长度投影n
到一个长度序列中n-1
- 例如,您可能希望在前面添加一个"虚拟"第一个元素.(或者更改方法以包含一个.)
以下是您如何使用它的示例:
var query = list.SelectWithPrevious((prev, cur) =>
new { ID = cur.ID, Date = cur.Date, DateDiff = (cur.Date - prev.Date).Days) });
Run Code Online (Sandbox Code Playgroud)
请注意,这将包括一个ID的最终结果以及下一个ID的第一个结果...您可能希望先按ID对序列进行分组.
Bra*_*mir 17
使用index获取上一个对象:
var LinqList = list.Select(
(myObject, index) =>
new {
ID = myObject.ID,
Date = myObject.Date,
Value = myObject.Value,
DiffToPrev = (index > 0 ? myObject.Value - list[index - 1].Value : 0)
}
);
Run Code Online (Sandbox Code Playgroud)
在C#4中,您可以使用Zip方法一次处理两个项目.像这样:
var list1 = list.Take(list.Count() - 1);
var list2 = list.Skip(1);
var diff = list1.Zip(list2, (item1, item2) => ...);
Run Code Online (Sandbox Code Playgroud)
修改Jon Skeet的答案以不跳过第一项:
public static IEnumerable<TResult> SelectWithPrev<TSource, TResult>
(this IEnumerable<TSource> source,
Func<TSource, TSource, bool, TResult> projection)
{
using (var iterator = source.GetEnumerator())
{
var isfirst = true;
var previous = default(TSource);
while (iterator.MoveNext())
{
yield return projection(iterator.Current, previous, isfirst);
isfirst = false;
previous = iterator.Current;
}
}
}
Run Code Online (Sandbox Code Playgroud)
几个主要区别...传递第三个bool参数,以指示它是否是可枚举的第一个元素。我还切换了当前/先前参数的顺序。
这是匹配的示例:
var query = list.SelectWithPrevious((cur, prev, isfirst) =>
new {
ID = cur.ID,
Date = cur.Date,
DateDiff = (isfirst ? cur.Date : cur.Date - prev.Date).Days);
});
Run Code Online (Sandbox Code Playgroud)