使用LINQ生成2-100素数的代码无法运行,请求技术协助
问题原因分析
你的代码思路是模拟埃氏筛法,但核心问题出在LINQ的延迟执行特性和闭包对循环变量的捕获上:
- LINQ查询(比如你的
from...select)默认是延迟执行的——也就是说,这些筛选逻辑不会在你赋值primes的时候立刻运行,而是要等到你在foreach里遍历primes的时候才会真正执行。 - 循环变量
i是被闭包捕获的,当最终执行所有LINQ查询时,i已经变成了循环结束后的最终值(也就是10,因为10²=100,循环到i=10就停止了)。这意味着所有的where条件都会用i=10来判断,完全违背了你原本想逐步筛除非素数的逻辑。
举个例子:原本你希望先用i=2筛掉所有偶数(除了2),再用i=3筛掉3的倍数(除了3),但最终执行的时候,所有筛选都变成了"如果数不能被10整除,或者等于10",结果自然不对。
解决方案
有两种简单的修复方式,都能解决这个问题:
方法1:捕获循环变量到局部变量
在循环内部把当前的i值存到一个局部变量里,让闭包捕获这个不会变化的局部变量,而不是循环变量i:
int limit = 100; IEnumerable<int> primes = Enumerable.Range(2, limit - 2 + 1); for (int i = 2; i * i <= limit; i++) { int currentI = i; // 关键:把当前i的值存到局部变量 primes = from item in primes where (item % currentI != 0) || (item == currentI) select item; } foreach (int prime in primes) Console.WriteLine(prime); Console.ReadKey();
方法2:立即执行LINQ查询
每次筛选后,用ToList()或ToArray()立即执行查询,把结果固化为集合,避免延迟执行带来的问题:
int limit = 100; IEnumerable<int> primes = Enumerable.Range(2, limit - 2 + 1); for (int i = 2; i * i <= limit; i++) { primes = (from item in primes where (item % i != 0) || (item == i) select item).ToList(); // 立即执行查询,固化结果 } foreach (int prime in primes) Console.WriteLine(prime); Console.ReadKey();
两种方法都能让你的埃氏筛法逻辑正常运行,方法2的可读性可能更好一些,因为它明确地把每次筛选的结果固定下来,和传统的埃氏筛法步骤更一致。
内容的提问来源于stack exchange,提问作者SlayerGames44
相关产品推荐
相关产品推荐

