【问题标题】:When do LINQ Lambdas execute in a foreach loopLINQ Lambda 何时在 foreach 循环中执行
【发布时间】:2015-10-20 01:25:04
【问题描述】:

所以,为了简短起见,我有这段代码,我在其中循环遍历字符串拆分的结果并将它们添加到列表中,如果它们之前没有在循环中发生过。这是代码。

var res = new List<string>();
foreach(string s in input.Split(new[] { ", " }, 
              StringSplitOptions.RemoveEmptyEntries))
{
    if(res.All(p => p != s))
        res.Add(s);
}

但在我写完这段代码后,Visual Studio 说我可以将部分循环转换为 LINQ。不过,我有点怀疑这是否可行。

基本上,我的问题是,lambda 表达式是在每个单独的循环中执行,还是在开始时只执行一次?

var res = new List<string>();
foreach (string s in input.Split(new[] { ", " }, 
              StringSplitOptions.RemoveEmptyEntries)
                          .Where(s => res.All(p => p != s)))
{
    res.Add(s);
}

【问题讨论】:

  • 你为什么不试试呢?
  • foreach 将枚举整个语句评估后产生的 IEnumerable。整个 LINQ 语句在 foreach 甚至开始之前进行评估
  • 一开始只有一次
  • @AlekDepler 实际上是在循环开始之前。 foreach 将在 调用 Where 返回最终的 IEnumerable 之后执行

标签: c# linq lambda


【解决方案1】:

这里是 Linq 查询的工作惰性求值示例。

List<int> vals = new List<int> {1, 1, 2, 2, 3, 4};
var res = new List<int>();
foreach (int s in vals.Where(s => 
                       { 
                           Console.WriteLine("lambda"); 
                           return s % 2 == 0; 
                       }))
{
    Console.WriteLine("loop");
}

输出将是

lambda
lambda
lambda
loop
lambda
loop
lambda
lambda
loop

如您所见,仅当 foreach 循环需要下一个元素时,才会评估 lambda

【讨论】:

  • 这是一个很好的例子,实际上回答了这个问题。
  • 实际上,我发现它并没有明确回答问题 “lambda 表达式是在每个单独的循环中执行,还是在开始时只执行一次?” 因为 Dmitry 说“仅在需要下一个元素时” 才会对其进行评估 - 这意味着实际上 lambda is 在每个单独的循环中评估了。我建议更改答案的措辞以更好地反映这一事实。
【解决方案2】:

基本上你只是想获得不同的值:

var res = input.Split(new[] { ", " }, StringSplitOptions.RemoveEmptyEntries)
               .Distinct()
               .ToList();

【讨论】:

  • 虽然这是一个更好的选择,但它不能回答问题。
  • @juharr 但是这个答案属于这里只是为了展示好的代码如何解决诸如“我不知道这段代码如何工作”之类的问题
【解决方案3】:

我在 Dmitry's answer 的基础上构建并让输出更加详细,以向您展示真正发生的事情。另请注意,作为Ufuk noted,有更好的方法来实现不同值的列表。

您可以自己测试一下,并在dotnetfiddle 中尝试一下。

示例如下:

List<int> input = new List<int> {1, 1, 2, 2, 3, 4};
var res = new List<int>();
foreach (int s in input.Where(s => 
            { 
                Console.WriteLine("lambda: s=" + s);
                Console.WriteLine("lambda: " + s + " contained in res? " + res.Contains(s));
                return !res.Contains(s);
            }))
{
    res.Add(s);
    Console.WriteLine("loop: " + s + " added to res");
    Console.WriteLine();
}

它产生以下输出:

lambda: s=1
lambda: 1 contained in res? False
loop: 1 added to res

lambda: s=1
lambda: 1 contained in res? True
lambda: s=2
lambda: 2 contained in res? False
loop: 2 added to res

lambda: s=2
lambda: 2 contained in res? True
lambda: s=3
lambda: 3 contained in res? False
loop: 3 added to res

lambda: s=4
lambda: 4 contained in res? False
loop: 4 added to res

【讨论】:

    猜你喜欢
    • 2011-04-26
    • 1970-01-01
    • 2013-06-26
    • 2017-02-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多