Я столкнулся с интересной проблемой в Powershell и не смог найти ее решения. Когда я использую Google (и нахожу такие вещи, как этот пост), ничего более сложного, чем то, что я пытаюсь сделать, не возникает, поэтому я решил опубликовать этот вопрос здесь.
Проблема связана с многомерными массивами с длиной внешнего массива, равной единице. Похоже, Powershell очень категоричен в отношении сглаживания массивов вроде @( @('A') )
становится @( 'A' )
. Вот первый фрагмент (подсказка>, кстати):
> $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'
).
У меня есть пара длинных примеров кода, поэтому я опубликовал их в конце. И, для справки, это Windows 7 Ultimate с установленными PSv2 и PSCX.
Рассмотрим пример кода 1: я создаю простой массив вручную с помощью оператора + =. Промежуточный массив $w
сглаживается и, следовательно, не добавляется к окончательному массиву правильно. Я нашел в Интернете решения для аналогичных проблем, которые в основном включают в себя установку запятой перед внутренним массивом, чтобы заставить внешний массив не сглаживаться, что действительно работает, но, опять же, я ищу решение, которое может создавать массивы внутри цикла ( зубчатый массив массивов, обрабатывающий файл CSS), поэтому, если я добавлю начальную запятую к одноэлементному массиву (реализованному как промежуточный массив $y
), я бы хотел сделать то же самое для других массивов (например, $z
), но это отрицательно влияет на то, как $z
добавляется к окончательному массиву.
Теперь рассмотрим пример кода 2: это ближе к реальной проблеме, с которой я столкнулся. Когда многомерный массив с одним элементом возвращается из функции, он выравнивается. Это правильно до того, как он покинет функцию. И снова это примеры, я действительно пытаюсь обработать файл, не зная, вернется ли функция с @( @( 'color', 'black') )
или с @( @( 'color', 'black'), @( 'background-color', 'white') )
Кто-нибудь сталкивался с этим, и кто-нибудь решил это? Я знаю, что могу создавать экземпляры объектов инфраструктуры, и я предполагаю, что все будет хорошо, если я создам объект [], или список ‹>, или что-то подобное, но я немного занимался этим и кое-что Конечно, похоже, что должен быть правильный способ сделать это (без необходимости создавать экземпляры настоящих объектов фреймворка).
Пример кода 1
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
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 '' }
}
function funA()
{
$ret = @()
$temp = @(0)
$temp[0] = @('p', 'q')
$ret += $temp
Display $ret 0 'Inside Function A'
return $ret # What about return ,$ret ? What about if $ret = @( @('p', 'q'), @('r', 's') ) -- would return ,$ret still work?
}
function funB()
{
$ret = @( ,@('r', 's') )
Display $ret 0 'Inside Function B'
return $ret
}
### Start Program
$z = funA
Display $z 0 'Return from Function A'
$z = funB
Display $z 0 'Return from Function B'
### Desired final value: @( @('p', 'q') ) and same for r,s
### As in the below:
#
# Inside Function A:
# [0]:
# [0]: 'p'
# [1]: 'q'
#
# Return from Function A:
# [0]:
# [0]: 'p'
# [1]: 'q'
Спасибо, Мэтт
$a = @( @( 'Test' ) )
do:$a = @( , @( 'Test' ) )
затем попробуйте$a[0][0]
и удивитесь, насколько ужасен синтаксис PowerShell. Добавление одного не только изменило это поведение, но и элемент по-прежнему [0] [0], а не [1] [0], как можно было предположить по количеству запятых в массиве .. оказывается, что в этом контексте эта запятая является не разделитель элементов. - person quetzalcoatl   schedule 21.02.2018