我使用BigInteger实现了斐波那契序列的简单实现:
internal class FibonacciEnumerator : IEnumerator<BigInteger>
{
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<BigInteger>
{
private readonly FibonacciEnumerator _f = new FibonacciEnumerator();
public IEnumerator<BigInteger> GetEnumerator(){return _f;}
IEnumerator IEnumerable.GetEnumerator(){return GetEnumerator();}
}
这是无限序列,因为MoveNext()
始终返回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(...)
有效?
答案 0 :(得分:51)
Skip(n)
无法访问Current
,只需拨打MoveNext()
n
次。
因此,您需要在MoveNext()
中执行增量,即the logical place for that operation anyway:
当前不会移动枚举器的位置,并且对Current的连续调用将返回相同的对象,直到调用MoveNext或Reset。
答案 1 :(得分:33)
CodeCaster的答案很明显 - 我只是想指出你真的不需要为这样的事情实现你自己的枚举:
public IEnumerable<BigInteger> FibonacciSequence()
{
var previous = BigInteger.One;
var current = BigInteger.Zero;
while (true)
{
yield return current;
var temp = current;
current += previous;
previous = temp;
}
}
编译器将为您创建枚举器和枚举。对于这样一个简单的可枚举,差异并不是那么大(你只需要避免大量的样板),但如果你真的需要比简单的递归函数更复杂的东西,它会产生巨大的差异。
答案 2 :(得分:5)
将您的逻辑移至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;
}
}
Skip(10)只是调用MoveNext
10次,然后是Current
。在MoveNext
中完成操作更有逻辑意义,而不是当前。