Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Force LINQ to execute again?

Tags:

c#

linq

I have got this code from a c# book:

int minSize = 10000;
var bigFiles = from file in GetAllFilesInDirectory(@"c:\")
 where new FileInfo(file).Length > minSize
 select file;

var filesOver10k = bigFiles.ToArray();

minSize = 100000;
var filesOver100k = bigFiles.ToArray();

minSize = 1000000;
var filesOver1MB = bigFiles.ToArray();

minSize = 10000000;
var filesOver10MB = bigFiles.ToArray();

The author says it will re-evaluate the query every time ToArray() is called. I want to do something similar. I need to query how many times each letter of the alphabet is used in a book; currently I'm using something like this:

string alphabet="abcdefghijklmnopqrstuvwxyz";

foreach(char a in alphabet)
{
 var stat_letter=book2.book.Sum(b=>b.chapter.Sum(l=>l.line.Sum(w=>w.word.ToLower().Count(c=>c.Equals(a)))));
 Console.WriteLine(a + ":" + stat_letter.ToString() );
}

The output I get:

a: 31278
b: 6263
c: 14561
[...]

I wanted to change it to work much like the book example:

char q = 'a';
var stat_letter = book2.book.Sum(b=>b.chapter.Sum(l=>l.line.Sum(w=>w.word.ToLower().Count(c=>c.Equals(q)))));

string alphabet="abcdefghijklmnopqrstuvwxyz";

foreach(char a in alphabet)
{
 q=a;
 Console.WriteLine(q + ":" + stat_letter.ToString() );
}

The output I get from this:

a: 31278
b: 31278
c: 31278
[...]

It looks like the query doesn't re-evaluate in this case. Is there any way to force it? Actually my motivation is to check if it would speed up the program execution, so if you think it would not, that is also something I'd like to know...

like image 932
Jack_of_no_trades Avatar asked Aug 08 '26 15:08

Jack_of_no_trades


2 Answers

Sum returns an int (using the overload you chose) not an IEnumerable. That means it's evaluated immediately, because it needs that int. The value of an int cannot be deferred.

While there are a few ways of re-structuring your code to defer execution, what I would prefer to do is to create a method (or a lambda, same concept really) that computes the value you want given the input you have, instead of mutating a variable that a query relies on.

Func<char, int> computeLetterCount = letter => book2.book.Sum(
    b=>b.chapter.Sum(
        l=>l.line.Sum(
            w=>w.word.ToLower().Count(c=>c.Equals(letter)))));

You can now write:

foreach(char a in alphabet)
{
     Console.WriteLine(a + ":" + computeLetterCount(a) );
}
like image 182
Servy Avatar answered Aug 10 '26 09:08

Servy


You calculated the value and saved it in variable. Of course it won't be reevaluated. But you can do the following:

Func<char,int> stat_letter_func = q => book2.book.Sum(b=>b.chapter.Sum(l=>l.line.Sum(w=>w.word.ToLower().Count(c=>c.Equals(q)))));

string alphabet="abcdefghijklmnopqrstuvwxyz";

foreach(char a in alphabet)
{
    Console.WriteLine(a + ":" + stat_letter_func(a).ToString() );
}
like image 43
Ulugbek Umirov Avatar answered Aug 10 '26 07:08

Ulugbek Umirov



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!