遍历 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
我正在尝试 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