开发者

In C# is there a function that correlates sequential values on a IEnumerable

I have a IEnumerable. I have a custom In开发者_如何学运维terval class which just has two DateTimes inside it. I want to convert the IEnumerable to IEnumerable where n DateTimes would enumerate to n-1 Intervals.

So if I had 1st Jan, 1st Feb and 1st Mar as the DateTime then I want two intervals out, 1st Jan/1st Feb and 1st Feb/1st March.

Is there an existing C# Linq function that does this. Something like the below Correlate...

IEnumerable<Interval> intervals = dttms.Correlate<DateTime, Interval>((dttm1, dttm2) => new Interval(dttm1, dttm2));

If not I'll just roll my own.


public static IEnumerable<Timespan> Intervals(this IEnumerable<DateTime> source)
{
    DateTime last;
    bool firstFlag = true;
    foreach( DateTime current in source)
    {
       if (firstFlag)
       {
          last = current;
          firstFlag = false;
          continue;
       }

       yield return current - last;
       last = current;
    }
}

or

public class Interval {DateTime Start; DateTime End;}

public static IEnumerable<Interval> Intervals(this IEnumerable<DateTime> source)
{
    DateTime last;
    bool firstFlag = true;
    foreach( DateTime current in source)
    {
       if (firstFlag)
       {
          last = current;
          firstFlag = false;
          continue;
       }

       yield return new Interval {Start = last, End = current};
       last = current;
    }
}

or very generic:

public static IEnumerable<U> Correlate<T,U>(this IEnumerable<T> source, Func<T,T,U> correlate)
{
    T last;
    bool firstFlag = true;
    foreach(T current in source)
    {
       if (firstFlag)
       {
          last = current;
          firstFlag = false;
          continue;
       }

       yield return correlate(last, current);
       last = current;
    }
}

var MyDateTimes = GetDateTimes(); 
var MyIntervals = MyDateTimes.Correlate((d1, d2) => new Interval {Start = d1, End = d2});


You could also just use Aggregate, Joel's answer would be better if you need in multiple scenarios:

    var dates = new List<DateTime> 
                { 
                    new DateTime(2010, 1, 1), 
                    new DateTime(2010, 2, 1), 
                    new DateTime(2010, 3, 1) 
                };
    var intervals = dates.Aggregate(new List<Interval>(), (ivls, d) =>
        {
            if (ivls.Count != dates.Count-1)
            {
                ivls.Add(new Interval(d,dates[ivls.Count + 1]));
            }
            return ivls;
        });


You can write your own extension method that will be able to do what you need.


Here's a slightly maddish solution based on LINQ:

var z = l.Aggregate(new Stack<KeyValuePair<DateTime, TimeSpan>>(),
                    (s, dt) =>
                      {
                        var ts = s.Count > 0 ? dt - s.Peek().Key : TimeSpan.Zero;
                        s.Push(new KeyValuePair<DateTime, TimeSpan>(dt, ts));
                        return s;
                      })
          .Where(kv=>!kv.Value.Equals(TimeSpan.Zero))
          .Select(kv => kv.Value)
          .ToList();

l is an enumerable of DateTimes.

But now that I see that you actually don't have TimeSpans but start and end times, this would look like that:

var z = l.Aggregate(new Stack<Interval>(),
(s, dt) =>
{
  s.Push(s.Count > 0 ? 
    new Interval { Start = s.Peek().End, End = dt } : new Interval { End = dt });
  return s;
})
.Where(v=> v.Start != default(DateTime))
.Reverse()
.ToList();
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜