【问题标题】:How does Linq know the name of an element?Linq 如何知道元素的名称?
【发布时间】:2022-01-19 14:15:14
【问题描述】:

我在 Codewars 上解决了一个 C# 初学者 Kata,要求返回一个只有 4 个字符名称的字符串 []。我使用了一个列表,它在 if 语句中填充,然后转换回字符串并返回。

我的问题是关于下面的最佳实践解决方案,稍后会介绍。

我知道作为参数出现的相同 string[] 会重新填充元素并返回。 但是程序如何知道数组的每个元素都称为“名称”,因为它以前从未提到过?

linq 是否知道具有单数名称的变量是复数名称组的元素,这里是“名称”?

感谢您的帮助!

using System;
using System.Collections.Generic;
using System.Linq;

public static class Kata {
  public static IEnumerable<string> FriendOrFoe (string[] names) {
    return names.Where(name => name.Length == 4);
  }
}

【问题讨论】:

  • name =&gt; name.Length == 4 是一个单参数代表。您已将参数命名为 name,但如果它是 banana,它也同样有效。数组 names 的各个元素没有自己的名称(当然,数组参数命名为 names 只是因为它也是这样声明的,giraffes 也可以工作)。
  • 它知道它被称为name,因为您在=&gt; 之前的部分中调用了它。您可以将name =&gt; name.Length == 4 更改为turnip =&gt; turnip.Length == 4,它的工作方式完全相同。
  • 我投票决定重新提出这个问题,因为我认为副本不合适。被选为重复的问题与此问题不同,并且没有一个答案是该问题的答案。此外,这是一个封闭的问题,它指向的 3 个重复项中的 1 个被删除。其他 2 个是关于 lambdas 的一般问题,没有一个答案显然能回答这个问题。这个问题的答案可能就藏在那个地段的某个地方,但肯定不容易找到。
  • 为了澄清,再次查看骗子的答案,他们都使用x 作为他们的 lambda 变量,但没有人说明他们为什么使用x,或者给出如何编写合适的建议变量的名称。我认为对于刚接触 lambda 语法的人来说,想知道代码的原始作者如何知道要使用什么变量名,因为在任何地方都没有 var x/var name 语句,这是一个完全合理(且独特)的问题。
  • @Tim 考虑到重复状态下的答案与那些 cmets 相同,为什么您认为重复状态没有回答问题?问题询问变量的定义位置,副本描述变量的定义位置。这就是问题的答案。

标签: c# linq


【解决方案1】:

我了解作为参数出现的相同字符串 [] 会重新填充元素并返回

我将简要地解决这个问题,因为这不是您要问的问题。这不是真的 - 不会再填充任何东西。原始数组没有改变,Where 是一个循环,它在数组上运行,并在提供给它的测试对该项目评估为真时有选择地从中发出项目。它这样做的方式是通过一个称为 yield return 的特殊构造,这是一种允许代码从方法返回然后重新输入并从之前停止的地方继续的方法,而不是从头开始方法的开始。只有一个数组,除非您从 Where 生成的字符串集中开始读取,否则不会执行循环/测试。如果您想了解更多相关信息,请发表评论。

继续..

linq 是否知道具有单数名称的变量是复数名称组的元素,这里是“名称”?

没有; IDE 知道变量 name,因为您选择在 Where( 之后调用它

也许将它与你已经知道的东西联系起来会有所帮助。编写这段代码是完全可以接受的:

public static class Kata {
  public static IEnumerable<string> FriendOrFoe (string[] names) {
    return names.Where(IsNameOfLengthFour);
  }

  static bool IsNameOfLengthFour(string name){
    return name.Length == 4;
  }
}

需要提供一些方法,该方法接受一个字符串并返回一个布尔值。它要求输入是一个字符串,因为它是在names 上调用的,它是一个字符串数组。如果它是数组中的整数,则传递给 Where 的方法必须采用 int

在 C# 中,经常需要让事情变得更紧凑,所以为了摆脱上面所有的冗长,我们有一种更紧凑的编写方法体的形式。让我们减少冗长的版本:

static bool IsNameOfLengthFour(string name){
  return name.Length == 4;
}

我们可以去掉返回类型,因为我们可以从返回的类型中猜测出来。我们也可以摆脱静态,如果我们从另一个静态内部调用它,就假设它是静态的,或者如果我们不是。我们也可以放弃输入类型,因为我们可以从输入的类型中猜测出来。

IsNameOfLengthFour(name){
  return name.Length == 4;
}

如果我们有一个只有一行的特殊语法并且必须是一个自动返回的值,我们可以去掉return{},因为它只有一行,所以我们不需要隔离多个语句:

IsNameOfLengthFour(name) => name.Length == 4

现在,如果我们要在某个名称无关紧要的地方使用它,我们实际上也不再需要方法名称,而且我们真的不需要 () 作为单个参数:

name => name.Length == 4

对于编译器来说,这样的表达式就足够了,它可以从中形成一个方法,并将其插入到一个期望方法接受一个字符串并返回一个布尔值的东西中。我们已经抛弃了我们人类喜欢的方法的所有绒毛(名称和标识符),并为编译器提供了它所需的原始螺母和螺栓 - 方法的逻辑。当编译器为我们将它们连接在一起时,它会重新创建其余的绒毛;我们永远无法在代码中的其他地方调用这个迷你方法,但我们不在乎。我们得到了我们想要的,这是一种很好的简洁的表达逻辑的方式:

Where(n => n.Length==4);

你做得很好,称这个迷你方法的参数是明智的。我看到x 使用了很多,当 X 是什么 发生变化时,它会变得非常混乱。例如:

names
  .Where(name => ...)
  .GroupBy(name => ...)
  .Select(g => g.First())
  .Where(name => ...)

Where 适用于您的名称数组,因此将参数调用到委托 namen 是一个好主意。 Where 将对其进行过滤,但最终它仍会发出一组名称字符串,因此在进入 GroupBy 的过程中将其称为 name 仍然是个好主意。但是 GroupBy 会产生一组 IGrouping,而不是一组的字符串,所以来自 GroupBy 的东西不再是名称。在下一个选择中,我将其称为 g 以反映它是一个分组,而不是一个名称,但我随后取分组中的第一项,即, 实际上, 一个名字.. 所以在最后我回去调用输入参数name 来反映它的本来面目..

当 LINQ 语句变得更加复杂时,正确命名这些参数确实很有帮助

注意:在这个答案中,我使用了“list”或“set”之类的词,我的意思是一般英语意义上的“array is a list of ..”,而不是专门的 C# @ 987654343@ 或HashSet&lt;xxx&gt; 感。如果您看到与 C# 类型对齐的小写单词,它们并不是指该特定类型

【讨论】:

  • 你真的是在胡扯——使用语法糖缩短的实际方法与 Func 或 Predicate 不同。
【解决方案2】:

我了解作为参数出现的 string[] 会重新填充元素并返回。

不,绝对不是。根据输入数组返回一个新的字符串序列。输入数组不会以任何方式修改或更改。

但是程序如何知道数组的每个元素都称为“名称”,因为它以前从未提到过?

name 是匿名函数的参数。 name 参数是一个基于上下文的字符串。这可以是xASDASDASD 或任何你想要的,但这里我们使用name,因为我们在每次调用时都有一个来自names 的“名称”。

因此,

  • names 是传入函数的字符串数组
  • .Where 基于谓词函数从当前数组返回一个新的IEnumerable&lt;string&gt;(例如,匹配返回 true,省略返回 false)
  • 谓词name =&gt; name.Length == 4接受一个字符串,如果字符串长度为4则返回true
  • 函数的返回是来自names的字符串,长度正好是4个字符

【讨论】:

  • 根据输入数组返回一个全新的数组 - 这不是真的
  • 我认为在初学者的答案中切换术语或对相同结构使用非规范术语不是一个好主意(例如“匿名函数”、“谓词”)。同样.Where 从不返回数组,所以这是错误的。
  • 谢谢,我认为“名称参数是基于上下文的字符串”就是我所要求的。 .Where 正在检查它知道是字符串的数组,并且第一次提到 name 是声明。检查!
  • @Garrag 可能还值得注意的是,有两个版本的 Where。一个是Where(list_of_strings, function_that_takes_a_string_and_returns_a_bool),另一个是Where(list_of_strings, function_that_takes_a_string_plus_int_and_returns_a_bool)。第一个参数表示调用 Where 的列表(因为 Where 是扩展方法)。二是功能。您使用了单参数版本,因此您不使用任何 ( ) 并只写一个名称。如果您使用第二个,您将提供例如.Where((str, idx) =&gt; ...),str为字符串,idx为索引
  • ..在列表中。例如,如果您想根据项目所在的位置返回,这可能很有用。Where((str, idx) =&gt; idx%2==0 &amp;&amp; str.StartsWith("A")) 仅返回每隔一个字符串,并且仅当它以 A 开头时。请始终记住,这只是一个迷你方法声明,然后您编写(str, idx) 就像你会写 public bool GetEveryOtherStartingWithA(string str, int idx){ ...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-09-17
  • 2015-04-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-07
  • 2022-08-24
相关资源
最近更新 更多