LINQ查询和子查询枚举计数在C#中?

时间:2012-12-04 15:30:35

标签: c# .net linq .net-4.0

假设我有这个问题:

  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 枚举的次数是多少次?

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

7 个答案:

答案 0 :(得分: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  

答案 1 :(得分: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. 您可以创建不同的实例来包装不同的基础序列,从而允许您在每个程序中检查多个序列,而不是在使用静态变量时检查一个序列。

答案 2 :(得分:3)

以下是如何估计枚举集合的快速计数:将集合包装在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(link to ideone),这意味着您的五个项目的集合已被枚举六次。

答案 3 :(得分: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)

答案 4 :(得分:1)

  

运行foreach时会枚举NUM次

简而言之,您的代码在道德上等同于:

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)的序列的一个枚举。
  3. 总的来说,我们列举Count + 1次。

    您可以通过引入本地来提升循环外的2查询,将其降低到Max

      

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

    使用原始数组并不容易。但是您可以编写自己的可枚举实现(可能包含数组)并向GetEnumerator方法添加一些检测。或者如果你想深入了解,那就去整个猪,并在MoveNextCurrent上编写一个包含检测的自定义枚举器。

答案 5 :(得分: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;

答案 6 :(得分:0)

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

在foreach循环外定义并初始化count变量,并在循环内将count变量增加为count++,以获得枚举次数。