在PowerShell中展平数组

ale*_*2k8 17 collections powershell

假设我们有:

$a = @(1, @(2, @(3)))
Run Code Online (Sandbox Code Playgroud)

我想变平$a获得@(1, 2, 3).

我找到了一个解决方案:

@($a | % {$_}).count
Run Code Online (Sandbox Code Playgroud)

但也许有更优雅的方式?

God*_*eke 14

管道是压扁嵌套结构的正确方法,所以我不确定什么会 "优雅".是的,语法看起来有点线条,但坦率地说是非常有用的.


ale*_*2k8 10

相同的代码,只包含在函数中:

function Flatten($a)
{
    ,@($a | % {$_})
}
Run Code Online (Sandbox Code Playgroud)

测试:

function AssertLength($expectedLength, $arr)
{
    if($ExpectedLength -eq $arr.length) 
    {
        Write-Host "OK"
    }
    else 
    {
        Write-Host "FAILURE"
    }
}

# Tests
AssertLength 0 (Flatten @())
AssertLength 1 (Flatten 1)
AssertLength 1 (Flatten @(1))
AssertLength 2 (Flatten @(1, 2))
AssertLength 2 (Flatten @(1, @(2)))
AssertLength 3 (Flatten @(1, @(2, @(3))))
Run Code Online (Sandbox Code Playgroud)

  • 使用逗号进行前缀会强制PowerShell返回一个数组,即使只有一个项目要返回.如果没有逗号,Powershell会将数组解析为与数组内容相同类型的单个对象.对于来自其他强类型语言的人来说,这可能会非常混乱. (3认同)

Bac*_*its 5

警告:请参阅最后的编辑!

Powershell v4.0 中引入的数组方法可能.ForEach()可以最优雅地解决这个问题。从性能角度来看,它的优点是不需要构建管道,因此在某些情况下它可能会表现得更好。

> $a.ForEach({$_}).Count
3
Run Code Online (Sandbox Code Playgroud)

如果您已经有管道,则展平数组的最简单方法是将其通过管道传输Write-Output

> $b = $a | Write-Output
> $b.Count
3
Run Code Online (Sandbox Code Playgroud)

--

编辑:上面的答案并不正确。它不会完全展平具有多个嵌套数组的数组。@SantiagoSquarzon 的答案有一个需要多次展开的深度嵌套数组的示例:

> $toUnroll = @(@(0,1),@(2,3),@(@(4,@(5,6)),@(7,8),9),10) # 11 elements
> $toUnroll.ForEach({$_}).Count
8

> $toUnroll.ForEach({$_}).ForEach({$_}).Count
10

> $toUnroll.ForEach({$_}).ForEach({$_}).ForEach({$_}).Count
11
Run Code Online (Sandbox Code Playgroud)

或者,也许更清楚:

> $toUnroll = @(@(0,1),@(2,3),@(@(4,@(5,6)),@(7,8),9),10) # 11 elements
### Unroll 0 times
> $toUnroll.ForEach({$_ | ConvertTo-Json -Compress})
[0,1]
[2,3]
[[4,[5,6]],[7,8],9]
10

### Unroll 1 times
> $toUnroll.ForEach({$_}).ForEach({$_ | ConvertTo-Json -Compress}) 
0
1
2
3
[4,[5,6]]
[7,8]
9
10

### Unroll 2 times
> $toUnroll.ForEach({$_}).ForEach({$_}).ForEach({$_ | ConvertTo-Json -Compress})
0
1
2
3
4
[5,6]
7
8
9
10

### Unroll 3 times
> $toUnroll.ForEach({$_}).ForEach({$_}).ForEach({$_}).ForEach({$_ | ConvertTo-Json -Compress})
0
1
2
3
4
5
6
7
8
9
10
Run Code Online (Sandbox Code Playgroud)