Итерация по 2 последовательным значениям IEnumerable - PullRequest
1 голос
/ 18 марта 2020

Для моего приложения я построил итератор, и мне нужно использовать каждое из значений, которые он выдает, вместе с предыдущим.

Например, рассмотрим следующий итератор, который выдает первые члены Последовательность Фибоначчи:

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 на самом деле не является частью последовательности.

Ответы [ 4 ]

2 голосов
/ 18 марта 2020

Просто верните текущее и предыдущее значения из вашего итератора:

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

1 голос
/ 18 марта 2020

Функция перечисления может отслеживать предыдущие и текущие значения и возвращать их в виде кортежа. Например, в примере Фибоначчи это будет примерно так:

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 голосов
/ 18 марта 2020

Ответ Haim770 правильный, если вы хотите изменить свой генератор. Однако вы также можете использовать метод общего назначения, который затем можно использовать с любым 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 перед параметром и поместите его в класс c, он будет работать как метод расширения)

0 голосов
/ 18 марта 2020

Некоторые последовательности Фибоначчи начинаются с 1 и 1 вместо 0 и 1. Так что, возможно, это решит вашу проблему.

...