将连续元素分组并选择第一个和最后一个元素

时间:2013-11-25 18:03:34

标签: c# .net linq c#-4.0

以下是我的清单

List<DateTime> ls_date =new List<DateTime>()
ls_date.Add("2013-12-02")
ls_date.Add("2013-12-03")
ls_date.Add("2013-12-04")
ls_date.Add("2013-12-05")
ls_date.Add("2013-12-08")
ls_date.Add("2013-12-12")
ls_date.Add("2013-12-13")
ls_date.Add("2013-12-14")

我想对连续日期进行分组,并选择该组的开始和结束日期

输出:

"2013-12-02"-"2013-12-05"
"2013-12-08"-"2013-12-08"
"2013-12-12"-"2013-12-14"

我的尝试:

public class sampleWithIntervals
{
 public DateTime startDate;
 public DateTime endDate;
}
    var data = ls_date
            .Select((s, i) => new { sample = s, index = i })                
            .GroupBy(si => new { date = si.sample.Date.AddDays(-si.index) })                
            .Select(g => new sampleWithIntervals()
            {
                startDate = g.Min(s => s.sample.Date),
                endDate = g.Max(s => s.sample.Date)

            });

我怎样才能做到这一点?

1 个答案:

答案 0 :(得分:3)

这是一个辅助函数,它根据一个函数对项目进行分组,该函数将当前项目和先前项目确定该项目是应该在现有组中还是新组中:

public static IEnumerable<IEnumerable<T>> GroupWhile<T>(
    this IEnumerable<T> source, Func<T, T, bool> predicate)
{
    using (var iterator = source.GetEnumerator())
    {
        if (!iterator.MoveNext())
            yield break;

        List<T> list = new List<T>() { iterator.Current };

        T previous = iterator.Current;

        while (iterator.MoveNext())
        {
            if (predicate(previous, iterator.Current))
            {
                list.Add(iterator.Current);
            }
            else
            {
                yield return list;
                list = new List<T>() { iterator.Current };
            }

            previous = iterator.Current;
        }
        yield return list;
    }
}

现在你可以写:

var intervals = dates.GroupWhile((prev, next) => 
        prev.Date.AddDays(1) == next.Date)
    .Select(g => new sampleWithIntervals()
    {
        startDate = g.Min(s => s.Date),
        endDate = g.Max(s => s.Date)
    });