I have a scenario where I have a list of objects with a datetime field in the object. I'm trying to find out if there is a way to use LINQ to group the list by sequential datetimes and return a subset of the list with the sequential datetimes as a range.
public virtual IList<LineItem> LineItems { get; set; }
...
public class LineItem
{
public virtual string Status { get; set; }
public virtual DateTime TransDate { get; set; }
...
}
So If I had 6 LineItem
s with Status = P
for all and
TransDate = { 8/1/2011 , 8/2/2011 , 8/3/2011 , 8/5/2011 , 8/6/2011 , 8/9/2011 }
respectively, I'd like to return the following list:
{ (P, 8/1/2011-8/3/2011) , (P,8/5/2011-8/6/2011) , (P,8/9/2011) }
Any thoughts? I can do this with iterating through the list manually and checking the TransDate to see if it's sequential, I am just looking for a more elegant (preferably LINQ) way of doing it. Thanks!
I would use a helper method like this:
private static IEnumerable<ICollection<T>> PartitionByPredicate<T>(
this IEnumerable<T> seq, Func<T, T, bool> split)
{
var buffer = new List<T>();
foreach (var x in seq)
{
if (buffer.Any() && split(buffer.Last(), x))
{
yield return buffer;
buffer = new List<T>();
}
buffer.Add(x);
}
if (buffer.Any())
yield return buffer;
}
And then:
var sorted = LineItems.OrderBy(i => i.TransDate);
var split = sorted.PartitionByPredicate(
(x, y) => (y.TransDate.Date - x.TransDate.Date).TotalDays > 1)
(edit: cleaned it up slightly, my first version was silly.)
I suggest you go with an iterator block implementation, as suggested by @mquander.
But here's a fun, pure LINQ solution that will work (albeit inefficiently), assuming the dates are distinct and chronological:
var groups = from item in LineItems
let startDate = item.TransDate
group item by LineItems.Select(lineItem => lineItem.TransDate)
.SkipWhile(endDate => endDate < startDate)
.TakeWhile((endDate, index) =>
startDate.AddDays(index) == endDate)
.Last();
//If required:
var groupsAsLists = groups.Select(g => g.ToList()).ToList();
This works by choosing the last sequential date in any date-sequence as the key for that sequence.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With