对于我的应用程序,我已经构建了一个迭代器,我需要使用它产生的每个值以及前一个值。
例如,考虑下面的迭代器,它产生斐波那契数列的第一项:
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
的第一个值实际上不是序列的一部分。
只需从迭代器中返回当前值和先前值:
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>
。
您可以使用枚举功能来跟踪先前和当前的值,并将它们作为元组返回。例如,在斐波那契示例中,将是这样的:
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);
}
}
某些斐波那契序列以1和1而不是0和1开头,所以也许可以解决您的问题。
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
并将其放在静态类中,它将用作扩展方法)