7

假设我有这个查询:

  int[] Numbers= new int[5]{5,2,3,4,5};

  var query =  from a in Numbers
      where a== Numbers.Max (n => n) //notice MAX  he should also get his value somehow
      select a;

foreach (var element in query)
  Console.WriteLine (element);
  • 运行时Numbers枚举 多少次foreach

  • 我该如何测试它(我的意思是,编写一个告诉我迭代次数的代码)

4

7 回答 7

3

这是检查计数的方法

void Main()
{
    var Numbers= new int[5]{5,2,3,4,5}.Select(n=>
    {
       Console.Write(n);
       return n;
    });

    var query =  from a in Numbers
                 where a== Numbers.Max (n => n)
                 select a;

    foreach (var element in query)
    {
          var v = element;
    }
}

这是输出

5 5 2 3 4 5 2 5 2 3 4 5 3 5 2 3 4 5 4 5 2 3 4 5 5 5 2 3 4 5  
于 2012-12-04T15:35:25.637 回答
3

它将被迭代 6 次。一次用于Where,每个元素一次用于Max

演示这一点的代码:

private static int count = 0;
public static IEnumerable<int> Regurgitate(IEnumerable<int> source)
{
    count++;
    Console.WriteLine("Iterated sequence {0} times", count);
    foreach (int i in source)
        yield return i;
}

int[] Numbers = new int[5] { 5, 2, 3, 4, 5 };

IEnumerable<int> sequence = Regurgitate(Numbers);

var query = from a in sequence
            where a == sequence.Max(n => n)
            select a;

它将打印“迭代序列 6 次”。

如果您打算使用它来试验其他情况,我们可以制作一个更通用、更灵活的包装器:

public class EnumerableWrapper<T> : IEnumerable<T>
{
    private IEnumerable<T> source;
    public EnumerableWrapper(IEnumerable<T> source)
    {
        this.source = source;
    }

    public int IterationsStarted { get; private set; }
    public int NumMoveNexts { get; private set; }
    public int IterationsFinished { get; private set; }

    public IEnumerator<T> GetEnumerator()
    {
        IterationsStarted++;

        foreach (T item in source)
        {
            NumMoveNexts++;
            yield return item;
        }

        IterationsFinished++;
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }

    public override string ToString()
    {
        return string.Format(
@"Iterations Started: {0}
Iterations Finished: {1}
Number of move next calls: {2}"
, IterationsStarted, IterationsFinished, NumMoveNexts);

    }
}

与其他功能相比,这有几个优点:

  1. 它记录了开始的迭代次数、完成的迭代次数以及所有序列递增的总次数。
  2. 您可以创建不同的实例来包装不同的底层序列,从而允许您检查每个程序的多个序列,而不是在使用静态变量时只检查一个。
于 2012-12-04T15:35:44.933 回答
3

以下是如何快速估算集合被枚举的次数的方法:将集合包装在 a 中CountedEnum<T>,并在每个 上增加计数器yield return,如下所示 -

static int counter = 0;

public static IEnumerable<T> CountedEnum<T>(IEnumerable<T> ee) {
    foreach (var e in ee) {
        counter++;
        yield return e;
    }
}

然后将您的数组声明更改为此,

var Numbers= CountedEnum(new int[5]{5,2,3,4,5});

运行您的查询,并打印counter. 对于您的查询,代码打印 30(指向 ideone 的链接),这意味着您的五个项目的集合已被枚举六次。

于 2012-12-04T15:40:51.630 回答
1

通过公共财产计数也产生 6。

private static int ncount = 0;
private int[] numbers= new int[5]{5,2,3,4,5};
public int[] Numbers 
{ 
    get
    {
        ncount++;
        Debug.WriteLine("Numbers Get " + ncount.ToString());  
        return numbers;
    }
}

这将计数减少到 2。
有道理,但我不会想到它。

int nmax = Numbers.Max(n => n);
var query = from a in Numbers
    where a == nmax //notice MAX  he should also get his value somehow
    //where a == Numbers.Max(n => n) //notice MAX  he should also get his value somehow
select a;
于 2012-12-04T16:13:05.900 回答
1

迭代次数必须等于query.Count()

所以要计算第一个查询结果中的元素数。

如果您要问其他问题,请澄清。

编辑

澄清后:

如果您在提供的代码中搜索迭代的总数,将会有7迭代(对于这个具体案例)。

var query =  from a in Numbers
      where a== Numbers.Max (n => n) //5 iterations to find MAX among 5 elements
      select a;

foreach (var element in query)
  Console.WriteLine (element); //2 iterations over resulting collection(in this question)
于 2012-12-04T15:33:27.583 回答
1

运行foreach时Numbers被枚举了多少次

粗略地说,您的代码在道德上等同于:

foreach(int a in Numbers)
{
   // 1. I've gotten rid of the unnecessary identity lambda. 
   // 2. Note that Max works by enumerating the entire source.
   var max = Numbers.Max();

   if(a == max)
     Console.WriteLine(a);
}

所以我们列举以下时间:

  1. 外循环序列的一个枚举 ( 1)。
  2. 每个成员的序列枚举 ( Count)。

所以总的来说,我们列举了Count + 1时间。

您可以通过引入本地查询2将查询提升到循环之外来解决这个问题。Max

我该如何测试它(我的意思是,编写一个告诉我迭代次数的代码)

使用原始数组并不容易。但是您可以编写自己的可枚举实现(可能包装了一个数组)并向该GetEnumerator方法添加一些检测。或者,如果您想更深入,请全力以赴并编写一个带有仪表的自定义枚举MoveNextCurrent

于 2012-12-04T15:45:50.353 回答
0

它将被迭代 6 次。一次用于Where,每个元素一次用于Max

在foreach循环外定义并初始化一个count变量,并像count++循环内一样递增count变量,得到枚举的次数。

于 2012-12-04T16:38:00.553 回答