简体   繁体   English

C# - TakeWhile和SkipWhile没有回来?

[英]C# - TakeWhile and SkipWhile not returning?

I have a class RekenReeks which returns numbers starting from 2, multiplied by 2. So {2,4,8,16,32,64} 我有一个RekenReeks类,它返回从2开始的数字,乘以2.所以{2,4,8,16,32,64}

Now I learned about the TakeWhile and SkipWhile methods as well as LINQ. 现在我了解了TakeWhile和SkipWhile方法以及LINQ。

So I have created 3 variables which should store exactly the same but my Console.WriteLine only prints selection1 and not 2 and 3. 所以我创建了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();
    }


}
}

Your sequence is unlimited (theoretically). 你的序列是无限的(理论上)。 You assume too much. 你假设太多了。 The functionality of your program cannot possibly know that your sequence is strictly monotonic increasing. 程序的功能不可能知道您的序列严格单调增加。

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

This will never stop. 这永远不会停止。 Because the where will always pull the next value, it does not know it's condition will be satisfied, it always has to check the next value. 因为where总是会拉的下一个值,它不知道它的条件将得到满足, 都将检查下一个值。

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

This will take values, while they are between 11 and 999. As your sequence starts with 2, it will stop right on the first value. 这将取值,而它们在11到999之间。当序列以2开头时,它将在第一个值上停止。

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

This will skip values while they are between 11 and 999. As the first is 2, it will skip none and therefore yield all . 这将在11到999之间跳过值。由于第一个是2,它将跳过无,因此产生全部

Both TakeWhile() and SkipWhile() start from very beginning of the sequence and stop taking/skipping when condition doesn't meet. 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);

For instance, if you put 例如,如果你放

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

since the 1st item of the reeks is 2 the condition n < 1000 && n > 10 doesn't meet TakeWhile stops and returns an empty sequence. 由于的第一项reeks2的条件n < 1000 && n > 10不符合TakeWhile停止并返回一个空的序列。 The right implemenation is 正确的实施是

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

If you want to cut off values from the middle of the sequence ( selection3 ) you have to use Where : 如果要从序列中间切除值( selection3 ),则必须使用Where

  var selection3 = reeks
    .Where(n => !(n > 1000 && n < 10)); // cut theses items off

Be careful when printing out an infinine sequence, .Take() is a good choice here: 打印出无限序列时要小心.Take .Take()是一个不错的选择:

   var selection3 = reeks
    .Where(n => n > 1000 && n < 10)
    .Take(100); // First 100 items in case the sequence is too long
var selection = from i in reeks
  where i > 10
  && i < 1000
  select i;

There's no reason for this to ever end. 这没有理由永远结束。 When i is 1024 it won't be yielded, but it will still check then if 2048 is less than 1000 , or 4096 is less than 1000 , or 8192 is less than 1000 and so on forever (eventually either overflow exception happens or n wraps around to 0 which then keeps being set to 0 * 2 which is still 0 ). i是1024时它将不会被产生,但它仍将检查然后2048是否小于1000 ,或4096小于1000 ,或8192小于1000等等(最终发生溢出异常或n包裹)大约为0 ,然后保持设置为0 * 2 ,仍为0 )。

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

The first value tried is 2 . 尝试的第一个值是2 This does not satisfy the predicate n < 1000 && n > 10 because it is not true that 2 > 10 . 这不满足谓词n < 1000 && n > 10因为2 > 10不是这样。 Therefore the taking stops. 因此停止了。

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

There is no value of n for which n > 1000 && n < 10 . 没有n值, n > 1000 && n < 10 Therefore this is the same as having no SkipWhile at all. 因此,这与没有SkipWhile完全相同。

It seems like what you want is: 看起来你想要的是:

reeks.SkipWhile(n => n >= 1000 || n <= 10).TakeWhile(n => n < 1000 && n > 10)

Which skips until the first number that meets the criteria is found, then takes all that meet it until the first that does not. 在找到满足条件的第一个数字之前会跳过,然后将所有符合条件的数字跳到第一个不符合条件的数字。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM