Domanda

Sto riscontrando un problema interessante in Powershell e non sono riuscito a trovare una soluzione.Quando cerco su Google (e trovo cose come questo post), non viene fuori nulla di così complicato come quello che sto cercando di fare, quindi ho pensato di pubblicare la domanda qui.

Il problema riguarda gli array multidimensionali con una lunghezza dell'array esterno pari a uno.Sembra che Powershell sia molto irremovibile nell'appiattire array come @( @('A') ) diventa @( 'A' ).Ecco il primo frammento (il prompt è >, tra l'altro):

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

Quindi mi piacerebbe averlo $a[0].gettype().isarray essere vero, in modo da poter indicizzare il valore come $a[0][0] (lo scenario del mondo reale sta elaborando array dinamici all'interno di un ciclo e mi piacerebbe ottenere i valori come $a[$i][$j], ma se l'elemento interno non viene riconosciuto come un array ma come una stringa (nel mio caso), inizi a indicizzare i caratteri della stringa, come in $a[0][0] -eq 'T').

Ho un paio di esempi di codice lunghi, quindi li ho pubblicati alla fine.E, per riferimento, questo è su Windows 7 Ultimate con PSv2 e PSCX installati.

Prendere in considerazione esempio di codice 1:Costruisco manualmente un semplice array utilizzando l'operatore +=.Matrice intermedia $w viene appiattito e di conseguenza non viene aggiunto correttamente all'array finale.Ho trovato soluzioni online per problemi simili, che sostanzialmente implicano l'inserimento di una virgola prima dell'array interno per forzare l'array esterno a non appiattirsi, il che funziona, ma ancora una volta, sto cercando una soluzione in grado di creare array all'interno di un ciclo ( un array frastagliato di array, elaborando un file CSS), quindi se aggiungo la virgola iniziale all'array a elemento singolo (implementato come array intermedio $y), mi piacerebbe fare lo stesso per altri array (come $z), ma ciò influisce negativamente sul modo $z viene aggiunto all'array finale.

Ora considera esempio di codice 2:Questo è più vicino al problema reale che sto riscontrando.Quando una funzione restituisce un array multidimensionale con un elemento, viene appiattito.È corretto prima di lasciare la funzione.E ancora, questi sono esempi, sto davvero cercando di elaborare un file senza dover sapere se la funzione tornerà con @( @( 'color', 'black') ) o con @( @( 'color', 'black'), @( 'background-color', 'white') )

Qualcuno ha riscontrato questo problema e qualcuno ha risolto il problema?So di poter istanziare oggetti framework e presumo che tutto andrà bene se creo un oggetto[], o un elenco<>, o qualcos'altro di simile, ma mi occupo di questo da un po' e qualcosa sicuramente sembra che ci debba essere un modo giusto per farlo (senza dover istanziare veri oggetti framework).

Esempio di codice 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'

Esempio di codice 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'

Grazie, Matt

È stato utile?

Soluzione

C'è un'altra domanda che inizia con lo stesso problema: Insidie ​​di PowerShell .Sembra che questo sia fatto in base alla progettazione.

Penso che se ritorni ,$ret invece di $ret, dovrebbe funzionare.

Altre due note:

  • puoi testare se l'elemento è array di $item -is [array] (solo perché assomiglia più a PowerShell ;)
  • @() ha effetto solo sugli elementi che non sono array.Se incatena @(@(@(1))), otterrai un array con un elemento int (@(@(@(1)))[0].gettype() restituisce Int32).
    COSÌ, @( ,@('r', 's') ) equivale a ,@('r', 's').

Altri suggerimenti

Ho provato quello che Stej detto e ha funzionato, con questo esempio:

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)'
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top