当前位置:  开发笔记 > 编程语言 > 正文

IEnumerable <T>跳过无限序列

如何解决《IEnumerable<T>跳过无限序列》经验,为你挑选了3个好方法。

我有一个使用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(...)工作?



1> CodeCaster..:

Skip(n)不访问Current,它只是调用MoveNext() n时间.

所以你需要执行增量MoveNext(),这是该操作的逻辑位置:

当前不会移动枚举器的位置,并且对Current的连续调用将返回相同的对象,直到调用MoveNext或Reset.



2> Luaan..:

CodeCaster的答案很明显 - 我只想指出你真的不需要为这样的事情实现你自己的枚举:

public IEnumerable FibonacciSequence()
{
  var previous = BigInteger.One;
  var current = BigInteger.Zero;

  while (true)
  {
    yield return current;

    var temp = current;
    current += previous;
    previous = temp;
  }
}

编译器将为您创建枚举器和枚举.对于这样一个简单的可枚举,区别并不是那么大(你只是避免大量的样板),但如果你真的需要比简单的递归函数更复杂的东西,它会产生巨大的差异.


这个.收益率回报是你的朋友.

3> Rob..:

将您的逻辑移动到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)简单地调用MoveNext10次​​,然后Current.将操作完成MoveNext而不是当前操作也更具逻辑性.

推荐阅读
ar_wen2402851455
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有