迭代IEnumerable的2个连续值

问题描述 投票:1回答:4

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

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

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的第一个值实际上不是序列的一部分。

c# foreach ienumerable
4个回答
2
投票

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

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<int, int>


1
投票

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

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

0
投票

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


0
投票

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

一起重用。
    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并将其放在静态类中,它将用作扩展方法)

© www.soinside.com 2019 - 2024. All rights reserved.