Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

LINQ query and sub-query enumeration count in C#?

suppose I have this query :

  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);
  • How many times does Numbers is enumerated when running the foreach ?

  • how can I test it ( I mean , writing a code which tells me the number of iterations)

like image 442
Royi Namir Avatar asked Dec 04 '12 15:12

Royi Namir


4 Answers

It will be iterated 6 times. Once for the Where and once per element for the Max.

The code to demonstrate this:

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;

It will print "Iterated sequence 6 times".

We could make a more general purpose wrapper that is more flexible, if you're planning to use this to experiment with other cases:

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);

    }
}

This has several advantages over the other function:

  1. It records both the number of iterations started, the number of iterations that were completed, and the total number of times all of the sequences were incremented.
  2. You can create different instances to wrap different underlying sequences, thus allowing you to inspect multiple sequences per program, instead of just one when using a static variable.
like image 184
Servy Avatar answered Nov 12 '22 22:11

Servy


Here is how you can estimate a quick count of the number of times the collection is enumerated: wrap your collection in a CountedEnum<T>, and increment counter on each yield return, like this --

static int counter = 0;

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

Then change your array declaration to this,

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

run your query, and print the counter. For your query, the code prints 30 (link to ideone), meaning that your collection of five items has been enumerated six times.

like image 33
Sergey Kalinichenko Avatar answered Nov 12 '22 22:11

Sergey Kalinichenko


Here is how you can check the count

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;
    }
}

Here is output

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  
like image 3
Arsen Mkrtchyan Avatar answered Nov 12 '22 23:11

Arsen Mkrtchyan


The number of iteration has to be equal to query.Count().

So to the count of the elements in the result of the first query.

If you're asking about something else, please clarify.

EDIT

After clarification:

if you're searching for total count of the iteration in the code provided, there will be 7 iterations (for this concrete case).

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

and

foreach (var element in query)
  Console.WriteLine (element); //2 iterations over resulting collection(in this question)
like image 1
Tigran Avatar answered Nov 12 '22 22:11

Tigran