【问题标题】:In C# is there a function that correlates sequential values on a IEnumerable在 C# 中是否有一个函数可以关联 IEnumerable 上的顺序值
【发布时间】:2010-03-25 00:44:44
【问题描述】:

我有一个 IEnumerable。我有一个自定义的 Interval 类,里面只有两个 DateTimes。我想将 IEnumerable 转换为 IEnumerable,其中 n DateTimes 将枚举为 n-1 个间隔。

因此,如果我将 1 月 1 日、2 月 1 日和 3 月 1 日作为 DateTime,那么我想要两个间隔,即 1 月 1 日/2 月 1 日和 2 月 1 日/3 月 1 日。

是否存在执行此操作的现有 C# Linq 函数。类似下面的东西关联...

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

如果没有,我就自己动手。

【问题讨论】:

  • 访客:您可能正在寻找Zip

标签: c# linq


【解决方案1】:
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】:

您也可以只使用聚合,如果您在多种情况下需要,乔尔的回答会更好:

    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】:

    您可以编写自己的扩展方法来满足您的需要。

    【讨论】:

      【解决方案4】:

      这是一个基于 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 是DateTimes 的可枚举。

      但现在我看到您实际上没有 TimeSpan 而是开始和结束时间,这看起来像这样:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2022-12-19
        • 2020-09-12
        • 2012-05-26
        • 1970-01-01
        • 1970-01-01
        • 2015-02-25
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多