在Powershell中避免不可知的锯齿状阵列扁平化

时间:2010-03-17 14:49:03

标签: arrays powershell jagged-arrays

我在Powershell中遇到了一个有趣的问题,并且无法找到解决方案。当我谷歌(并找到this post之类的东西)时,没有任何涉及到我想要做的事情,所以我想我会在这里发布问题。

问题与外部数组长度为1的多维数组有关。似乎Powershell对于@( @('A') )变为@( 'A' )这样的扁平化数组非常坚定。这是第一个片段(提示符是>,btw):

> $a =  @( @( 'Test' ) )
> $a.gettype().isarray
True
> $a[0].gettype().isarray
False

所以,我希望$a[0].gettype().isarray成为真,这样我就可以将值索引为$a[0][0](真实场景是在循环内处理动态数组,而且我会喜欢将值设为$a[$i][$j],但如果内部项不被识别为数组而是字符串(在我的情况下),则开始索引字符串的字符,如$a[0][0] -eq 'T'中所示)。

我有几个很长的代码示例,所以我最后发布了它们。并且,作为参考,这是在安装了PSv2和PSCX的Windows 7旗舰版上。

考虑代码示例1 :我使用+ =运算符手动构建一个简单数组。中间数组$w被展平,因此未正确添加到最终数组中。我已经在网上找到类似问题的解决方案,基本上是在内部数组之前插入一个逗号来强制外部数组不会变平,这确实有效,但同样,我正在寻找一种可以在循环内构建数组的解决方案(一个锯齿状的数组数组,处理一个CSS文件),所以如果我将前导逗号添加到单个元素数组(实现为中间数组$y),我想对其他数组做同样的事情(如{ {1}}),但这会对$z添加到最终数组的方式产生负面影响。

现在考虑代码示例2 :这更接近我遇到的实际问题。当从函数返回具有一个元素的多维数组时,它将被展平。它离开函数之前是正确的。再一次,这些都是示例,我真的试图处理一个文件,而不必知道该函数是否会回复$z@( @( 'color', 'black') )

有没有人遇到这个,有没有人解决这个问题?我知道我可以实例化框架对象,我假设如果我创建一个对象[],或者一个列表<>或类似的东西,一切都会好的,但我一直在处理这个问题。确实看来必须有一种正确的方法来实现这一点(无需实例化真正的框架对象)。

代码示例1

@( @( 'color', 'black'), @( 'background-color', 'white') )

代码示例2

function Display($x, [int]$indent, [string]$title)
{
  if($title -ne '') { write-host "$title`: " -foregroundcolor cyan -nonewline }
  if(!$x.GetType().IsArray)
  { write-host "'$x'" -foregroundcolor cyan }
  else
  {
    write-host ''
    $s = new-object string(' ', $indent)
    for($i = 0; $i -lt $x.length; $i++)
    {
      write-host "$s[$i]: " -nonewline -foregroundcolor cyan
      Display $x[$i] $($indent+1)
    }
  }
  if($title -ne '') { write-host '' }
}


### Start Program
$final = @( @( 'a', 'b' ), @('c'))
Display $final 0 'Initial Value'

### How do we do this part ??? ###########
                                        ##
$w = @( @('d', 'e') )                   ##
$x = @( @('f', 'g'), @('h') )           ##
# But now $w is flat, $w.length = 2     ##
                                        ##
                                        ##
# Even if we put a leading comma (,)    ##
# in front of the array, $y will work   ##
# but $w will not. This can be a        ##
# problem inside a loop where you don't ##
# know the length of the array, and you ##
# need to put a comma in front of       ##
# single- and multidimensional arrays.  ##
$y = @( ,@('D', 'E') )                  ##
$z = @( ,@('F', 'G'), @('H') )          ##
                                        ##
                                        ##
##########################################

$final += $w
$final += $x
$final += $y
$final += $z
Display $final 0 'Final Value'


### Desired final value: @( @('a', 'b'), @('c'), @('d', 'e'), @('f', 'g'), @('h'), @('D', 'E'), @('F', 'G'), @('H') )
### As in the below:
# 
# Initial Value:
# [0]:
#  [0]: 'a'
#  [1]: 'b'
# [1]:
#  [0]: 'c'
# 
# Final Value:
# [0]:
#  [0]: 'a'
#  [1]: 'b'
# [1]:
#  [0]: 'c'
# [2]:
#  [0]: 'd'
#  [1]: 'e'
# [3]:
#  [0]: 'f'
#  [1]: 'g'
# [4]:
#  [0]: 'h'
# [5]:
#  [0]: 'D'
#  [1]: 'E'
# [6]:
#  [0]: 'F'
#  [1]: 'G'
# [7]:
#  [0]: 'H'

谢谢,马特

2 个答案:

答案 0 :(得分:6)

另一个问题始于同一问题:Powershell pitfalls。看起来这是通过设计完成的。

我认为如果您返回,$ret而不是$ret,它应该有效。

还有两个注释:

  • 你可以测试,如果项目是$item -is [array]的数组(只是因为它看起来更像PowerShell;)
  • @()仅对非数组的项有效。如果链接@(@(@(1))),您将得到一个包含一个int项的数组(@(@(@(1)))[0].gettype()返回Int32)。
    因此,@( ,@('r', 's') ),@('r', 's')相同。< / LI>

答案 1 :(得分:0)

我尝试了stej所说的并且它有效,使用这个例子:

function funC([int]$numOfPairs)
{
  $ret = @()
  if($numOfPairs -eq 1)
  { $ret = ,@('r','s') }
  elseif($numOfPairs -eq 2)
  { $ret = @('r','s'),@('t','u') }
  else
  { $ret = @('r','s'),@('t','u'),@('v','w') }

  Display $ret 0 "Inside Function C ($numOfPairs)"
  return ,$ret
}


### Start Program

$z = funC 1
Display $z 0 'Return from Function C(1)'
$z = funC 2
Display $z 0 'Return from Function C(2)'
$z = funC 3
Display $z 0 'Return from Function C(3)'