遍历 IEnumerable returns 什么都没有

Loop through IEnumerable returns nothing

我正在尝试 return 列表 (lookupData) 中匹配特定条件(由 lookupKey 数组中的元素定义)的元素。

但是,如果我将输出定义为 IEnumerable 类型,则不会 returned。当 i = 2 时, 'Output' 变量在最后一个循环中重置。为什么它不起作用?

我想将输出变量保留为 IEnumerable 而不是 List,因为它效率更高。

   var lookupKey = new string[] { "Male", "China" };

   var lookupData = new List<string[]>();
   lookupData.Add(new string[] { "Male", "China" });
   lookupData.Add(new string[] { "Male", "America" });
   lookupData.Add(new string[] { "Female", "UK" });

   IEnumerable<string[]> output = lookupData;

   for (int i = 0; i < 2; i++)
   {
      output = output.Where(x => x[i] == lookupKey[i]);
   }

您可以使用 LINQ 中的 Where()All()Contains()

var output = lookupData
    .Where(data => data.All(item => lookupKey.Contains(item)))

注意: 如果您希望结果是 List<string[]> 而不是 IEnumerable<string[]>,请在查询末尾添加 ToList() .

您的搜索逻辑不太正确,您不需要 for 循环,因为它会覆盖 where 条件。这是一种可能的搜索方式,它将 return IEnumerable<string[]>:

var output = lookupData.Where(g => g[0] == lookupKey[0] && g[1] == lookupKey[1]);

使用 List<string[]> 而不是 IEnumerable<string[]>。因为 IEnumerable<string[]> 将在需要获取值时执行查询(例如 Count() 或 Loop)。因此,在您的情况下,当您尝试在 IEnumerable 对象上循环时,在条件的 for 循环之后,它将评估 .Where(x => x[i] == lookupKey[i])。所以在这里它将有 i = 3。 这就是您遇到问题的原因。

如果您使用 List<string[]> 那么它会立即在您使用的 for 循环内计算表达式。

更新后的代码如下所示。

var lookupKey = new string[] { "Male", "China" };

var lookupData = new List<string[]>();
lookupData.Add(new string[] { "Male", "China" });
lookupData.Add(new string[] { "Male", "America" });
lookupData.Add(new string[] { "Female", "UK" });

List<string[]> output = lookupData;

for (int i = 0; i < 2; i++)
{
   output = output.Where(x => x[i] == lookupKey[i]).ToList();
}

IEnumerable vs List - What to Use? How do they work?希望这个回答可能对您有所帮助。

i 循环变量未按您预期的方式捕获。解决方法是在循环内部引入一个局部变量:

for (int i = 0; i < 2; i++)
{
    var index = i;
    output = output.Where(x => x[index] == lookupKey[index]);
}

在此处查找有关捕获循环变量的更多信息:Captured variable in a loop in C#

简单来说,当您在 lambda 中使用变量时,它会将变量的范围扩展到 lambda/the 即使在 for 循环结束并且您引用了 i 之后,lambda 仍然可以访问 i,在 for 循环初始值设定项中建立,已超出范围。

因为 lambda 的 LINQ 执行实际上只在您请求 result/enumerate 可枚举时发生(这可能是几个小时后)lambda 将看到 i 的值,因为它是由for 循环,即 2,这意味着您的 lambda 遇到索引超出范围

在最新版本的 c# 中,foreach 循环的内部行为已被修改,因此循环的每次迭代 returns 来自正在迭代的任何变量的副本,因此您应该能够更改您的for 到 lookupKey 上的 foreach 中,它将按您预期的那样工作。不过,这是一种难以阅读和理解的模式,我认为您应该考虑将其更改为:

var output = lookupData.Where(arr => arr.SequenceEquals(lookupKey));

如果数据集很大并且经常搜索,请考虑使用一个容器来对项目进行哈希处理,因为现在这种方法需要大量的字符串比较——lookupData 中的条目数乘以条目数在 lookupKey