我有一个使用BigInteger的Fibonacci序列的简单实现:
internal class FibonacciEnumerator : IEnumerator{ private BigInteger _previous = 1; private BigInteger _current = 0; public void Dispose(){} public bool MoveNext() {return true;} public void Reset() { _previous = 1; _current = 0; } public BigInteger Current { get { var temp = _current; _current += _previous; _previous = temp; return _current; } } object IEnumerator.Current { get { return Current; } } } internal class FibonacciSequence : IEnumerable { private readonly FibonacciEnumerator _f = new FibonacciEnumerator(); public IEnumerator GetEnumerator(){return _f;} IEnumerator IEnumerable.GetEnumerator(){return GetEnumerator();} }
这是一个无限的序列,因为MoveNext()
always总是返回true.
使用时调用
var fs = new FibonacciSequence(); fs.Take(10).ToList().ForEach(_ => Console.WriteLine(_));
输出符合预期(1,1,2,3,5,8,...)
我想选择10个项目,但从第100个位置开始.我试过通过它来调用它
fs.Skip(100).Take(10).ToList().ForEach(_ => Console.WriteLine(_));
但这不起作用,因为它从头开始输出十个元素(即输出再次是1,1,2,3,5,8,......).
我可以通过调用SkipWhile跳过它
fs.SkipWhile((b,index) => index < 100).Take(10).ToList().ForEach(_ => Console.WriteLine(_));
从第100个元素开始正确输出10个元素.
是否有其他需要/可以在枚举器中实现的Skip(...)
工作?
Skip(n)
不访问Current
,它只是调用MoveNext()
n
时间.
所以你需要执行增量MoveNext()
,这是该操作的逻辑位置:
当前不会移动枚举器的位置,并且对Current的连续调用将返回相同的对象,直到调用MoveNext或Reset.
CodeCaster的答案很明显 - 我只想指出你真的不需要为这样的事情实现你自己的枚举:
public IEnumerableFibonacciSequence() { var previous = BigInteger.One; var current = BigInteger.Zero; while (true) { yield return current; var temp = current; current += previous; previous = temp; } }
编译器将为您创建枚举器和枚举.对于这样一个简单的可枚举,区别并不是那么大(你只是避免大量的样板),但如果你真的需要比简单的递归函数更复杂的东西,它会产生巨大的差异.
将您的逻辑移动到MoveNext
:
public bool MoveNext() { var temp = _current; _current += _previous; _previous = temp; return true; } public void Reset() { _previous = 1; _current = 0; } public BigInteger Current { get { return _current; } }
跳过(10)简单地调用MoveNext
10次,然后Current
.将操作完成MoveNext
而不是当前操作也更具逻辑性.