C# - TakeWhile和SkipWhile没有回来?

时间:2016-02-26 13:37:06

标签: c# linq lambda expression

我有一个RekenReeks类,它返回从2开始的数字,乘以2.所以{2,4,8,16,32,64}

现在我了解了TakeWhile和SkipWhile方法以及LINQ。

所以我创建了3个应该存储完全相同的变量,但我的Console.WriteLine只打印selection1而不是2和3。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication2
{
    class Program
    {
        static void Main(string[] args)
        {
            RekenReeks reeks = new RekenReeks(2, n => n * 2);
            var selection = from i in reeks
                        where i > 10
                        && i < 1000
                        select i;

        var selection2 = reeks.TakeWhile(n => n < 1000 && n > 10);

        var selection3 = reeks.SkipWhile(n => n > 1000 && n < 10);

        foreach (int i in selection)
        {
            Console.WriteLine("selection1 {0}",i);
        }

        foreach (int i in selection2)
        {
            Console.WriteLine("selection2 {0}", i);
        }

        foreach (int i in selection3)
        {
            Console.WriteLine("selection3 {0}", i);
        }

        Console.ReadLine();
    }
}


public class RekenReeks : IEnumerable<int>
{
    Func<int, int> getNew;
    int number;
    public RekenReeks(int starton, Func<int, int> getNewThing)
    {
        getNew = getNewThing;
        number = starton;
    }

    public IEnumerator<int> GetEnumerator()
    {
        yield return number;
        for (; ; )
        {

            yield return getNew(number);
            number = getNew(number);

        }

    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        return this.GetEnumerator();
    }


}
}

3 个答案:

答案 0 :(得分:7)

你的序列是无限的(理论上)。你假设太多了。程序的功能不可能知道您的序列严格单调增加。

var selection = from i in reeks
                    where i > 10
                    && i < 1000
                    select i;

这永远不会停止。由于where将始终提取下一个值,因此不知道它的条件是否满足,它总是 来检查下一个值。

    var selection2 = reeks.TakeWhile(n => n < 1000 && n > 10);

这将取值,而它们介于11和999之间。当序列以2开头时,它将在第一个值上停止。

    var selection3 = reeks.SkipWhile(n => n > 1000 && n < 10);

这将在11到999之间跳过值。由于第一个是2,它将跳过无,因此产生 all

答案 1 :(得分:3)

hasBeenSet = true; setTimeout(function(){ hasBeenSet = false}, 60000); TakeWhile()都从序列的最开始处开始,并在条件不符合时停止/跳过。

SkipWhile()

例如,如果你把

  // I've redesigned your ReekenReeks
  // [2, 4, 8, 16, 32, 64, ..., 2**30]
  var reeks = Enumerable
    .Range(1, 30)
    .Select(index => 1 << index);

由于 var selection2 = reeks .TakeWhile(n => n < 1000 && n > 10); 的第一项reeks,条件2不符合n < 1000 && n > 10停止并返回序列。正确的实施是

TakeWhile

如果您想从序列( var selection2 = reeks .SkipWhile(n => n <= 10) .TakeWhile(n => n < 1000); )的中间中删除值,则必须使用selection3

Where

打印 infinine 序列时要小心, var selection3 = reeks .Where(n => !(n > 1000 && n < 10)); // cut theses items off 是个不错的选择:

.Take()

答案 2 :(得分:1)

var selection = from i in reeks
  where i > 10
  && i < 1000
  select i;

没有理由永远这样做。当i为1024时,它将无法获得,但如果2048小于1000,或4096小于{{1},它仍会检查}},或1000小于8192等等(最终要么发生溢出异常,要么1000回绕到n,然后将其设置为{{1}它仍然是0)。

0 * 2

尝试的第一个值是0。这不符合谓词reeks.TakeWhile(n => n < 1000 && n > 10) ,因为2不正确。因此停止了。

n < 1000 && n > 10

2 > 10没有reeks.SkipWhile(n => n > 1000 && n < 10) 的值。因此,这与完全没有n相同。

看起来你想要的是:

n > 1000 && n < 10

在找到满足条件的第一个数字之前跳过,然后将所有符合条件的数字跳到第一个不符合条件的数字。