Arrays Powershell阵列平坦化是如何工作的?

Arrays Powershell阵列平坦化是如何工作的?,arrays,powershell,Arrays,Powershell,请注意: C:\> $x = @(1) C:\> $x = @($x,2) C:\> $x = @($x,3) C:\> $x = @($x,4) C:\> $x = @($x,5) C:\> $x.Length 2 C:\> @($x |% { $_ }).Length 3 C:\> $x Length : 2 LongLength : 2 Rank : 1 SyncRoot : {Sy

请注意:

C:\> $x = @(1)
C:\> $x = @($x,2)
C:\> $x = @($x,3)
C:\> $x = @($x,4)
C:\> $x = @($x,5)
C:\> $x.Length
2
C:\> @($x |% { $_ }).Length
3
C:\> $x


Length         : 2
LongLength     : 2
Rank           : 1
SyncRoot       : {System.Object[] 2, 3}
IsReadOnly     : False
IsFixedSize    : True
IsSynchronized : False
Count          : 2

4
5


C:\>
我原以为管道会把名单弄平。但事实并非如此。我做错了什么?

Re:

我原以为管道会把名单弄平。但事实并非如此。我做错了什么

  • 实际上,当您键入
    $x
    (您的上一个命令)时,确实发生了一些
    平坦化。请注意,前面的
    $x.Length
    为您提供了2个元素,而
    $x
    为您提供了3个元素:

  • 数组(显示其属性,而不是内容)
  • 项目
    4
  • 项目
    5
  • 这表明确实发生了“一级平坦化”。我希望你能承认这算是平淡

  • 现在,从你对结果的不满来看,你相当疑惑:

    “为什么不‘一路走’?”

我还想知道这种行为,我学到的是:

1.PowerShell行为背后的明显规则: 当脚本(至少包括脚本文件、脚本块、函数)向调用者生成结果时,在脚本求值时会发生“一级”平坦化。 也就是说,如果一个脚本生成一个数组,其中的任何项也都是数组,那么这些项的数组将在它们的位置(在它们的同级之间)连接起来。这种展平只在顶级数组上发生一次,因此只有其直接的“子数组”将展平,而不会展平任何更深的数组

看看你的例子,这种扁平化发生在你身上,实际上有两种说法:

  • 在上一条语句中,已经提到的
    C:\>$x
    ,当shell执行评估并返回3项时(它没有发生在
    $x.Length
    上,因为
    $x
    评估没有向调用shell屈服)
  • 但也在更早的时候,使用
    @($x |%{$}).Length
    ,它还返回了3个项目。这一个得到了平坦化,因为
    %{${code>是一个“脚本块”,它向调用它的
    %
    (它本身是
    ForEach对象
    的别名)引入了新的求值和结果。没有其他产量,因为
    .Length
    紧随其后,所以它只导致一个水平再次变平
  • 2.文档 嗯,我找不到一个文档部分专门讨论这种行为。我甚至不知道如何寻找它,因为。。。该机制将如何命名?”阵列结果的平坦化'?在这些关键字下找不到任何相关内容。我承认,没有在任何地方显著地看到这种文档是非常令人惊讶的,因为隐式地更改数据结构可能是一件非常危险的事情

    3.为什么要变平? 由于缺少文档,我只能推测,但仔细想想,这似乎是PowerShell内置的,事实上是其结构的一部分。总的来说,我认为通过减少所需的修改,可以更容易地向现有代码添加更多行为

    详细地说,考虑这两种语言的性质,当然这是肯定的:

  • 允许只使用多个
    写入输出添加到返回数组中。这是需要的,特别是因为shell脚本始终处理多个项目(第一个明显的是多行文本)
  • 能够使用现有组件/子程序编写程序。我想说,直觉上是需要的
  • 现在,如果没有平坦化的行为,那么将一组包含多个输出语句的语句提取到一个子例程中意味着您突然得到一个数组,在这里您以前只有平坦的多个
    写输出。现在,如果在原始顶级例程中没有输出,这不是问题(因为您可以只返回数组),但是如果仍然有多个写入输出,这是问题。您需要创建一个数组变量并将每个
    写入输出
    更改为其附录,或者使用
    for
    循环每个提取的子例程(因为
    ForEach对象
    ,也称为
    %
    ForEach
    ,在其自己的内部作用域中运行)

    也许这个问题的另一种解决方案可能是使用一个特殊的操作符(如JavaScript)返回数组的每个项,但PowerShell似乎选择了最小的操作符,或者选择了最小的写入来实现这一点——您只需将整个数组正常地
    写入输出即可(因此,对于单个项目,该操作符的工作方式类似于JS
    yield
    ,对于数组,该操作符的工作方式类似于一个
    yield*

    值得注意的是,我认为这样做是以不希望阵列被展平的情况为代价的,我想,这在很大程度上考虑了PowerShell的角情况使用。是其中之一。有趣的是,答案实际上指向了一个解决方法:它使用
    (,$someArrayItem)
    在“也是数组的项目”周围创建一个额外数组,将该项目展平,而不是内部)

    4.为什么不“一路走”? 好吧,同样,没有文档,这只能是猜测。但我能想到的是:

    虽然“一路”展平似乎是最常见的需要展平的情况下所需要的行为,但默认情况下构建它确实是让人们处于不需要展平的情况下,没有任何简单的解决方法(因为额外添加嵌套级别是徒劳的)。让他们摆脱困境的唯一方法是使用不同于数组的数据结构。这将是相当昂贵的

    这里有点离题:
    这可能太过一厢情愿了,但如果PowerShell愿意的话,这种令人惊讶的行为并不是PowerShell无法进化出来的。对于