Combining consecutive dates into ranges

后端 未结 2 479
悲哀的现实
悲哀的现实 2020-12-18 12:44

I have a List of objects

public class sample
{
 public DateTime Date;
 public string content;
}

I want to be able to create a list of new o

2条回答
  •  忘掉有多难
    2020-12-18 13:25

    I have this SplitBy extension method where you can specify a delimiter predicate with which the collection will be split, just like string.Split.

    public static IEnumerable> SplitBy(this IEnumerable source, 
                                                         Func delimiterPredicate,
                                                         bool includeEmptyEntries = false, 
                                                         bool includeSeparator = false)
    {
        var l = new List();
        foreach (var x in source)
        {
            if (!delimiterPredicate(x))
                l.Add(x);
            else
            {
                if (includeEmptyEntries || l.Count != 0)
                {
                    if (includeSeparator)
                        l.Add(x);
    
                    yield return l;
                }
    
                l = new List();
            }
        }
        if (l.Count != 0 || includeEmptyEntries)
            yield return l;
    }
    

    So now splitting is easy if you can specify a consecutive streak delimiter. For that you can order the collection and zip with adjacent items, so now the difference in dates in the two resultant columns can act as delimiter.

    var ordered = samples.OrderBy(x => x.content).ThenBy(x => x.Date).ToArray();
    var result = ordered.Zip(ordered.Skip(1).Append(new sample()), (start, end) => new { start, end })
                        .SplitBy(x => x.end.Date - x.start.Date != TimeSpan.FromDays(1), true, true)
                        .Select(x => x.Select(p => p.start).ToArray())
                        .Where(x => x.Any())
                        .Select(x => new sampleWithIntervals
                        {
                            content = x.First().content,
                            startDate = x.First().Date,
                            endDate = x.Last().Date
                        });
    

    new sample() is a dummy instance used to get the Zip correctly. The Append method is to append items to a IEnumerable<> sequence, and it goes like this:

    public static IEnumerable Append(this IEnumerable source, params T[] items)
    {
        return source.Concat(items);
    }
    

    Note: this doesn't preserve the initial order. If you want the original order, select the index initially and form an anonymous class right away (Select((x, i) => new { x, i })) and at the last stage sort on the basis of index before selecting appropriate type.

提交回复
热议问题