I'm trying to prepare data for a graph using LINQ.
The problem that i cant solve is how to calculate the "difference to previous.
the result I expect is
ID= 1, Date= Now, DiffToPrev= 0;
ID= 1, Date= Now+1, DiffToPrev= 3;
ID= 1, Date= Now+2, DiffToPrev= 7;
ID= 1, Date= Now+3, DiffToPrev= -6;
etc...
Can You help me create such a query ?
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();
}
}
}
One option (for LINQ to Objects) would be to create your own LINQ operator:
This enables you to perform your projection using only a single pass of the source sequence, which is always a bonus (imagine running it over a large log file).
Note that it will project a sequence of length
n
into a sequence of lengthn-1
- you may want to prepend a "dummy" first element, for example. (Or change the method to include one.)Here's an example of how you'd use it:
Note that this will include the final result of one ID with the first result of the next ID... you may wish to group your sequence by ID first.
In C#4 you can use the Zip method in order to process two items at a time. Like this:
Yet another mod on Jon Skeet's version (thanks for your solution +1). Except this is returning an enumerable of tuples.
This is NOT returning the first because it's about returning the intermediate between items.
use it like:
OR
OR (like jon shows)
Modification of Jon Skeet's answer to not skip the first item:
A few key differences... passes a third bool parameter to indicate if it is the first element of the enumerable. I also switched the order of the current/previous parameters.
Here's the matching example:
Further to Felix Ungman's post above, below is an example of how you can achieve the data you need making use of Zip():
Basically, you are zipping two versions of the same list but the first version (the current list) begins at the 2nd element in the collection, otherwise a difference would always differ the same element, giving a difference of zero.
I hope this makes sense,
Dave
Use index to get previous object: