代码之家  ›  专栏  ›  技术社区  ›  Mike Q

在C中是否有一个函数将IEnumerable上的序列值关联起来

  •  2
  • Mike Q  · 技术社区  · 16 年前

    我有一个数不清的。我有一个自定义的间隔类,其中只有两个日期时间。我想将IEnumerable转换为IEnumerable,其中N个DateTimes将枚举为N-1个间隔。

    所以如果我有1月1日,2月1日和3月1日作为日期时间,那么我想要两个时间间隔,1月1日/2月1日和2月1日/3月1日。

    有没有一个现有的c linq函数可以做到这一点。像下面这样的关联…

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

    如果不行,我就自己滚。

    4 回复  |  直到 16 年前
        1
  •  6
  •   Joel Coehoorn    16 年前
    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;
        }
    }
    

    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;
        }
    }
    

    或者非常普通:

    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});
    
        2
  •  1
  •   David    16 年前

    你也可以使用聚合,如果你需要在多个场景中使用joel的答案会更好:

        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;
            });
    
        3
  •  0
  •   Andrew Bezzub    16 年前

    您可以编写自己的扩展方法,这样就可以做您需要的事情。

        4
  •  0
  •   flq    16 年前

    以下是一个基于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是可枚举的 DateTime S.

    但现在我看到你实际上没有时间跨度,只有开始和结束时间,这看起来像是:

    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();