【问题标题】:Iterate on 2 consecutive values of an IEnumerable迭代 IEnumerable 的 2 个连续值
【发布时间】:2020-03-18 13:56:21
【问题描述】:

对于我的应用程序,我构建了一个迭代器,我需要使用它产生的每个值以及前一个值。

例如,考虑以下迭代器,它产生斐波那契数列的第一项:

public static IEnumerable<int> GetFibonacciNumbers(int count)
{
    int a = 0;
    int b = 1;
    int i = 0;

    while (i < count)
    {
        yield return a;
        int temp = a;
        a = b;
        b = temp + b;
        i++;
    }
}

现在我想使用这个枚举器来计算越来越准确的黄金比例估计值,这意味着我需要将产生的值与之前的值一起使用。以下方法有效:

static void Main(string[] args)
{
    int fib0 = 0;
    foreach (int fib1 in GetFibonacciNumbers(10))
    {
        var phi = (double)fib1 / fib0;
        Console.WriteLine(phi);
        fib0 = fib1;
    }
}

问题在于phi 的第一个值是错误的,因为fib0 使用的第一个值实际上并不是序列的一部分。

【问题讨论】:

  • 你不只需要从 1 而不是 0 开始 fib 序列吗?
  • 为什么不在你的迭代器中yield return (a, b)
  • @Sean 斐波那契数列只是说明问题的一个简单示例,我实际想要使用的迭代器要复杂得多。
  • @gazoh - 但如果你不向我们展示代码,那么你怎么能指望我们提供帮助?
  • @haim770 我没有想到这一点,它工作得很好,如果你把它作为答案发布,我很乐意接受。

标签: c# foreach ienumerable


【解决方案1】:

只需从迭代器中返回当前值和以前的值:

public static IEnumerable<(int prevValue, int currentValue)> GetFibonacciNumbers(int count)
{
    int a = 0;
    int b = 1;
    int i = 0;

    while (i < count)
    {
        yield return (a, b);

        int temp = a;
        a = b;
        b = temp + b;
        i++;
    }
}

以上使用 C# 7.0 Tuple Syntax,但您也可以轻松地将其转换为使用常规 Tuple&lt;int, int&gt;

【讨论】:

    【解决方案2】:

    您可以让枚举函数跟踪先前和当前值并将它们作为元组返回。例如,在斐波那契示例中,它将是这样的:

    static IEnumerable<(int Previous, int Current)> GetFibonacciNumbers(int count)
    {
        var (previous, current) = (0, 1);
    
        for(int i = 0; i < count; i++)
        {
            yield return (previous, current);
    
            (previous, current) = (current, previous + current);
        }
    }
    

    【讨论】:

    • 我喜欢这种优雅的方法
    【解决方案3】:

    Haim770's answer 是正确的,如果你想修改你的生成器。但是,您可能还想使用一种通用方法,然后您可以将其与任何IEnumerable&lt;T&gt; 重用:

        public static IEnumerable<(T prevValue, T currentValue)> OverlappingPairs<T>(IEnumerable<T> source)
        {
            bool first = true;
            T previous = default;
            foreach (var item in source)
            {
                if (!first)
                    yield return (previous, item);
                first = false;
                previous = item;
            }
        }
    

    (当然,如果你在参数前加上this并将它放在一个静态类中,它就会作为一个扩展方法工作)

    【讨论】:

      【解决方案4】:

      一些斐波那契数列以 1 和 1 而不是 0 和 1 开头。所以也许这可以解决您的问题。

      【讨论】:

      • 斐波那契数列只是说明问题的一个简单示例,我实际想要使用的迭代器要复杂得多。
      猜你喜欢
      • 2015-05-27
      • 1970-01-01
      • 2011-06-20
      • 2011-03-26
      • 1970-01-01
      • 2017-10-22
      • 1970-01-01
      • 1970-01-01
      • 2017-08-08
      相关资源
      最近更新 更多