通过IEnumerable循环不返回任何内容

时间:2020-01-30 05:06:44

标签: c# linq ienumerable

我试图返回与特定条件(由lookupKey数组中的元素所定义)匹配的List(lookupData)中的一个元素。

但是,如果将输出定义为IEnumerable类型,则不会返回任何结果。当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]);
   }

5 个答案:

答案 0 :(得分:2)

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#

答案 1 :(得分:1)

简单来说,当您在lambda中使用变量时,它将变量的范围扩展到lambda /即使在for循环结束并且您对i的引用(在for中建立)之后,lambda仍然可以访问i循环初始化程序,已超出范围。

由于仅当您请求结果/枚举可枚举时(可能会在数小时后),lambda的LINQ执行才会真正发生,因此lambda将看到i的值,因为它是由for循环留下的,即2,这意味着您的Lambda遇到的索引超出范围

在最新版本的C#中,修改了foreach循环的内部行为,以便循环的每次迭代都从被迭代的内容返回变量的副本,因此您应该能够将lookupKey的for更改为foreach它将按您期望的那样工作。尽管这是一种阅读和理解的尴尬模式,但我认为您应该考虑将其更改为以下内容:

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

如果数据集很大并且经常搜索,请考虑使用一个将项目散列的容器,因为现在此方法需要大量的字符串比较-lookupData中的条目数乘以lookupKey中的条目数

答案 2 :(得分:0)

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

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

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

答案 3 :(得分:0)

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

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

答案 4 :(得分:0)

使用SELECT p.id AS product_id, count(users.id) AS num_users FROM products p LEFT JOIN users ON p.id = users.product_id AND users.account_id = 1 GROUP BY p.id ORDER BY p.id 代替List<string[]>。由于IEnumerable<string[]>将在需要获取值(例如Count()或Loop)时执行查询。因此,在情况为条件的for循环之后,当您尝试在此时IEnumerable<string[]>对象上循环时,它将评估IEnumerable。因此,这里的i = 3。 这是造成您问题的原因。

如果您使用.Where(x => x[i] == lookupKey[i]),它将在您使用的for循环内立即计算表达式。

您更新的代码如下所示。

List<string[]>

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