2015-11-05 83 views
3

嵌套数组鉴于此输入:压扁在PowerShell中

$values = @(1, @(2, 3), $null, @(@(4), 5), 6) 

什么是必要创建了

1,2,3,4,5,6 

干净的迭代/管道?

条件:

  • 它不应该包括在输出$null
  • 即使输入为$ null或所有输入的值为$ null,它也应该会产生一个空数组。

加成:

  • 它应该显示[1,2,3,4,5,6]作为ConvertTo-Json -Compress
  • 结果它应当优选是清洁的和令人难忘的,即非拜占庭管操纵优选的,没有对自定义函数依赖性,如果该完全有可能。

我见过Flatten array in PowerShell,那里的解决方案似乎并不符合条件。

+0

您是否需要仅拼合数组?其他类型的收藏呢? – PetSerAl

+0

非常欢迎支持所有类型集合的解决方案。我们的目标是能够遍历整个事物,调用'Select-Object'等,而不会被'$ null'干扰或者受到嵌套深度的影响。 – Tomalak

+0

我非常想要构建一个递归函数,但是这会违反奖金 – Matt

回答

3

为了完整起见,因为它可以帮助我想包括其他用户覆盖大部分的标准,除了一个非常简单的递归函数...

应该最好是干净的,难忘的,即非拜占庭管操纵个优选d,如果可能的话,不依赖于自定义函数。

我知道[你]可以这样做,是[你]自但也许它可以帮助别人。在谈到PowerShell时,我已经看到了这一点,简称为展开阵列。如果你继续搜索,那么这个词可能会有更多的成果。

使用$input它是如何打算我们做一个相当简单的功能。如果传递的元素之一是一个数组元素,那么我们再次调用该函数,直到我们减少到原始值。

function Flatten-Array{ 
    $input | ForEach-Object{ 
     if ($_ -is [array]){$_ | Flatten-Array}else{$_} 
    } | Where-Object{![string]::IsNullorEmpty($_)} 
    # | Where-Object{$_} would also work. 
} 

所以样本通话将

@(1, @(2, 3), $null, @(@(4), 5), 6) | Flatten-Array | ConvertTo-Json -Compress 

哪个网络[1,2,3,4,5,6]$null s覆盖了几个简单的Where条款之一。

+0

你的'Flatten-Array'不会放弃'$ null'。试试这个:@(1,@(2,3),$ null,@(@(4),5),6)| Flatten-Array | %GetType'。它是'ConvertTo-Json'谁删除'$ null'。 – PetSerAl

+0

@PetSerAl谢谢。一个简单的地方涵盖了。我试图保持简洁。 – Matt

+0

@Xalorous'$ input'是一个[自动变量](https://technet.microsoft.com/en-us/library/hh847768.aspx)。它不需要定义。不知道为什么它不适合你。 – Matt

1

注意:不要使用$input作为变量名,它是一个自动管道枚举器,它不会像您期望的那样工作。 (即与ForEach-Object

两轮流水线将拉平该结构对你来说,ConvertTo-Json -Compress会自动离开了$null值:

PS C:\> $NestedArray = @(1, @(2, 3), $null, @(@(4), 5), 6) 
PS C:\> $FlatArray = $NestedArray | ForEach-Object { $_ } | ForEach-Object { $_ } 
PS C:\> $FlatArray | ConvertTo-Json -Compress 
[1,2,3,4,5,6] 
+0

'$ input'只是一个虚拟的名字,我已经改变了,谢谢你的提示。关于N水平呢?如果不事先了解嵌套深度,是否有办法做到这一点?另外,我希望在'ConvertTo-Json'之前''null'out *,提到它只是让我明白什么结果是数据结构。 – Tomalak

+0

由于这不是递归的,它不会处理超过3个级别。 – Xalorous

3

你可以用递归命令做到这一点:

$values = (1, (2, 3), $null, (,4, 5), 6) 

$values|&{ 
    process{ 
     if($null -ne [System.Management.Automation.LanguagePrimitives]::GetEnumerator($_)){ 
      $_|&$MyInvocation.MyCommand.ScriptBlock 
     }elseif($null -ne $_){ 
      $_ 
     } 
    } 
} 

但是你应该可以肯定,你不喜欢这个传递的东西作为输入:

$values[0]=$values=,0 
+0

我从你那里学到很多东西! – Matt

+0

这并不完全符合“非拜占庭”的部分,但它非常有趣和有益。谢谢! – Tomalak

1

这里是一个递归Flatten-Array函数,它不使用流水线:

$values = @(1, @(2, 3), $null, @(@(4), 5), 6) 

function Flatten-Array{ 
    param (
     [array] $inputArray 
    ) 

    foreach ($item in $inputArray){ 
     # skip $nulls 
     if ($item -ne $null) { 
      # recurse for arrays 
      if ($item.gettype().BaseType -eq [System.Array]) { 
       Flatten-Array $item 
      } 
      else { 
      # output non-arrays 
       $item 
      } 
     } 
    } 
} 

Flatten-Array $values | %{$_.gettype()} 
+0

Mh,不使用流水线的好处是什么? – Tomalak

+0

你问它不包括拜占庭流水线。这是最简单,最容易记住我可以开发的解决方案。经过几个小时的抛光,这可以转换为高级功能并被认为是可重用的代码。如果这是我需要经常做的事情,我会考虑将其添加到我的个人资料或自定义模块中。 YMMV,但在脚本中,我倾向于返回对象的函数,而在CLI中,我将使用别名和流水线。 – Xalorous

+0

我不是故意说我找到流水线byzanzine。我的意思是说我不喜欢拜占庭流水线,这是一个区别。拜见PetSerAl的答案,尽可能让人大开眼界,以拜占庭流水线为例。 – Tomalak

4

@(1, @(2, 3), $null, @(@(4), 5), 6) | %{$_} | ?{$_ -ne $null}

输出:

1 
2 
3 
4 
5 
6 

ForEach-Object的小命令(%)默认变平阵列。