我从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();
作者说,每次调用ToArray()时,它都会重新评估查询。我想做类似的事情。我需要查询书中每个字母的使用次数;目前我正在使用这样的东西:
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() );
}
我得到的输出:
a: 31278
b: 6263
c: 14561
[...]
我想把它改成工作,就像书中的例子一样:
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() );
}
我得到的输出:
a: 31278
b: 31278
c: 31278
[...]
在这种情况下,查询似乎没有重新评估。有没有办法强迫它?实际上我的动机是检查它是否会加快程序的执行速度,所以如果你认为它不会,那也是我想知道的......
答案 0 :(得分:7)
Sum
返回int
(使用您选择的重载)而不是IEnumerable
。这意味着它会立即进行评估,因为它需要int
。 <{1}}的值不能推迟。
虽然有几种方法可以重新构建代码以推迟执行,但我更喜欢做的是创建一个方法(或者一个lambda,相同的概念),根据你的输入计算你想要的值。而不是改变查询所依赖的变量。
int
您现在可以写:
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)))));
答案 1 :(得分:2)
您计算了该值并将其保存在变量中。当然,它不会被重新评估。 但是你可以做到以下几点:
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() );
}
答案 2 :(得分:-1)
不是查询不重新评估,而是LINQ在可能的情况下使用延迟执行。如果您正在使用延迟执行查看它,并且每次调用ToArray()
时,查询都会在该时间点对集合执行。在您的示例中,一个或多个查询运算符(Sum
肯定会)强制执行,因此如果您一直尝试反复运行它并不重要,查询已经针对集合运行那个时间点和实际结果是什么存储在该变量中。基本上,只需使用您的工作代码,因为这是执行它的惯用方法。