تجنب صفيف خشن لاأدري تسطيح في PowerShell
-
20-09-2019 - |
سؤال
أنا أواجه مشكلة مثيرة للاهتمام في PowerShell ، ولم أتمكن من العثور على حل لها. عندما أكون جوجل (وأجد أشياء مثل هذا المشنور) ، لا شيء يشارك تمامًا مثل ما أحاول القيام به ، لذلك اعتقدت أنني سأقوم بنشر السؤال هنا.
تتعلق المشكلة بصفائف متعددة الأبعاد بطول صفيف خارجي. يبدو أن 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'
شكرا يا مات
المحلول
هناك سؤال آخر يبدأ بنفس المشكلة: مطبات PowerShell . يبدو أن هذا يتم عن طريق التصميم.
أعتقد أنه إذا عدت ,$ret
بدلاً من $ret
, ، يجب أن تعمل.
ملاحظات أخرى:
- يمكنك الاختبار ، إذا كان العنصر صفيفًا
$item -is [array]
(لمجرد أنها تبدو أشبه باورشيل ؛) @()
له تأثير فقط على العناصر التي ليست صفائف. إذا كنت سلسلة@(@(@(1)))
, ، ستحصل على صفيف مع عنصر واحد (@(@(@(1)))[0].gettype()
إرجاع int32).
لذا،@( ,@('r', 's') )
بالضبط مثل,@('r', 's')
.
نصائح أخرى
جربت ما قاله ستيج وعمل ، باستخدام هذا المثال:
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)'