Tudo o que você queria saber sobre arrays

As matrizes são uma característica fundamental da linguagem da maioria das linguagens de programação. Eles são uma coleção de valores ou objetos que são difíceis de evitar. Vamos dar uma olhada nos arrays e tudo o que eles têm a oferecer.

Nota

A versão original deste artigo apareceu no blog escrito por @KevinMarquette. A equipe do PowerShell agradece Kevin por compartilhar esse conteúdo conosco. Por favor, confira seu blog em PowerShellExplained.com.

O que é uma matriz?

Vou começar com uma descrição técnica básica do que são matrizes e como elas são usadas pela maioria das linguagens de programação antes de mudar para as outras maneiras como o PowerShell faz uso delas.

Uma matriz é uma estrutura de dados que serve como uma coleção de vários itens. Você pode iterar sobre a matriz ou acessar itens individuais usando um índice. A matriz é criada como um bloco sequencial de memória onde cada valor é armazenado ao lado do outro.

Abordarei cada um desses detalhes à medida que formos avançando.

Utilização básica

Como as matrizes são um recurso tão básico do PowerShell, há uma sintaxe simples para trabalhar com elas no PowerShell.

Criar uma matriz

Uma matriz vazia pode ser criada usando @()

PS> $data = @()
PS> $data.count
0

Podemos criar uma matriz e semeá-la com valores apenas colocando-os entre @() parênteses.

PS> $data = @('Zero','One','Two','Three')
PS> $data.count
4

PS> $data
Zero
One
Two
Three

Esta matriz tem 4 itens. Quando chamamos a $data variável, vemos a lista dos nossos itens. Se for uma matriz de strings, obteremos uma linha por string.

Podemos declarar uma matriz em várias linhas. A vírgula é opcional neste caso e geralmente deixada de fora.

$data = @(
    'Zero'
    'One'
    'Two'
    'Three'
)

Eu prefiro declarar minhas matrizes em várias linhas assim. Não só fica mais fácil de ler quando você tem vários itens, mas também torna mais fácil comparar com versões anteriores ao usar o controle do código-fonte.

Outra sintaxe

É comumente entendido que @() é a sintaxe para criar uma matriz, mas listas separadas por vírgulas funcionam na maioria das vezes.

$data = 'Zero','One','Two','Three'

Write-Output para criar matrizes

Um pequeno truque legal que vale a pena mencionar é que você pode usar Write-Output para criar rapidamente strings no console.

$data = Write-Output Zero One Two Three

Isso é útil porque você não precisa colocar aspas ao redor das cadeias de caracteres quando o parâmetro aceita cadeias de caracteres. Eu nunca faria isso em um roteiro, mas é jogo limpo no console.

Acesso a itens

Agora que você tem uma matriz com itens, talvez queira acessar e atualizar esses itens.

Desvio

Para acessar itens individuais, usamos os colchetes com um valor de deslocamento a partir de [] 0. É assim que obtemos o primeiro item em nossa matriz:

PS> $data = 'Zero','One','Two','Three'
PS> $data[0]
Zero

A razão pela qual usamos zero aqui é porque o primeiro item está no início da lista, então usamos um deslocamento de 0 itens para chegar a ele. Para chegar ao segundo item, precisaríamos usar um deslocamento de 1 para pular o primeiro item.

PS> $data[1]
One

Isso significaria que o último item está no deslocamento 3.

PS> $data[3]
Three

Índice

Agora você pode ver por que eu escolhi os valores que eu fiz para este exemplo. Eu apresentei isso como um offset porque é o que realmente é, mas esse offset é mais comumente referido como um índice. Um índice que começa em 0. Para o resto deste artigo, chamarei o deslocamento de índice.

Truques especiais de índice

Na maioria dos idiomas, você só pode especificar um único número como índice e recebe um único item de volta. O PowerShell é muito mais flexível. Você pode usar vários índices ao mesmo tempo. Ao fornecer uma lista de índices, podemos selecionar vários itens.

PS> $data[0,2,3]
Zero
Two
Three

Os itens são retornados com base na ordem dos índices fornecidos. Se você duplicar um índice, obterá esse item duas vezes.

PS> $data[3,0,3]
Three
Zero
Three

Podemos especificar uma sequência de números com o operador embutido .. .

PS> $data[1..3]
One
Two
Three

Isso funciona ao contrário também.

PS> $data[3..1]
Three
Two
One

Você pode usar valores de índice negativos para compensar a partir do final. Então, se você precisar do último item da lista, você pode usar -1.

PS> $data[-1]
Three

Uma palavra de cautela aqui com o .. operador. A seqüência 0..-1 e -1..0 avaliar para os valores 0,-1 e -1,0. É fácil ver $data[0..-1] e pensar que enumeraria todos os itens se você esquecer esse detalhe. $data[0..-1] Dá-lhe o mesmo valor que $data[0,-1] lhe dando o primeiro e o último item na matriz (e nenhum dos outros valores). Aqui está um exemplo maior:

PS> $a = 1,2,3,4,5,6,7,8
PS> $a[2..-1]
3
2
1
8

Isto é o mesmo que:

PS> $a[2,1,0,-1]
3
2
1
8

Fora dos limites

Na maioria dos idiomas, se você tentar acessar um índice de um item que já passou do final da matriz, obterá algum tipo de erro ou uma exceção. O PowerShell silenciosamente não retorna nada.

PS> $null -eq $data[9000]
True

Não é possível indexar em uma matriz nula

Se a variável for $null e você tentar indexá-la como uma matriz, você receberá uma System.Management.Automation.RuntimeException exceção com a mensagem Cannot index into a null array.

PS> $empty = $null
PS> $empty[0]
Error: Cannot index into a null array.

Portanto, certifique-se de que suas matrizes não $null estão antes de tentar acessar elementos dentro delas.

Count

Matrizes e outras coleções têm uma propriedade count que informa quantos itens estão na matriz.

PS> $data.count
4

O PowerShell 3.0 adicionou uma propriedade count à maioria dos objetos. você pode ter um único objeto e ele deve lhe dar uma contagem de 1.

PS> $date = Get-Date
PS> $date.count
1

Mesmo $null tem uma propriedade count, exceto que retorna.0

PS> $null.count
0

Há algumas armadilhas aqui que irei revisitar quando abordar a verificação de $null matrizes vazias ou vazias mais adiante neste artigo.

Erros off-by-one

Um erro de programação comum é criado porque as matrizes começam no índice 0. Os erros off-by-one podem ser introduzidos de duas maneiras.

A primeira é pensando mentalmente que você quer o segundo item e usando um índice de 2 e realmente obtendo o terceiro item. Ou pensando que você tem quatro itens e quer o último item, então você usa a contagem para acessar o último item.

$data[ $data.count ]

O PowerShell está perfeitamente feliz em permitir que você faça isso e forneça exatamente qual item existe no índice 4: $null. Você deve estar usando $data.count - 1 ou o -1 que aprendemos acima.

PS> $data[ $data.count - 1 ]
Three

É aqui que você pode usar o -1 índice para obter o último elemento.

PS> $data[ -1 ]
Three

Lee Dailey também me apontou que podemos usar $data.GetUpperBound(0) para obter o número máximo do índice.

PS> $data.GetUpperBound(0)
3
PS> $data[ $data.GetUpperBound(0) ]
Three

A segunda maneira mais comum é ao iterar a lista e não parar no momento certo. Vou revisitar isso quando falarmos sobre o uso do for loop.

Atualizando itens

Podemos usar o mesmo índice para atualizar itens existentes na matriz. Isso nos dá acesso direto para atualizar itens individuais.

$data[2] = 'dos'
$data[3] = 'tres'

Se tentarmos atualizar um item que já passou do último elemento, obtemos um Index was outside the bounds of the array. erro.

PS> $data[4] = 'four'
Index was outside the bounds of the array.
At line:1 char:1
+ $data[4] = 'four'
+ ~~~~~~~~~~~~~
+ CategoryInfo          : OperationStopped: (:) [], IndexOutOfRangeException
+ FullyQualifiedErrorId : System.IndexOutOfRangeException

Voltarei a isso mais tarde, quando falar sobre como fazer uma matriz maior.

Iteração

Em algum momento, talvez seja necessário percorrer ou iterar toda a lista e executar alguma ação para cada item na matriz.

Pipeline

As matrizes e o pipeline do PowerShell destinam-se um ao outro. Esta é uma das maneiras mais simples de processar sobre esses valores. Quando você passa uma matriz para um pipeline, cada item dentro da matriz é processado individualmente.

PS> $data = 'Zero','One','Two','Three'
PS> $data | ForEach-Object {"Item: [$PSItem]"}
Item: [Zero]
Item: [One]
Item: [Two]
Item: [Three]

Se você ainda não viu $PSItem antes, saiba que é a mesma coisa $_que . Você pode usar qualquer um deles porque ambos representam o objeto atual no pipeline.

Loop ForEach

O ForEach loop funciona bem com coleções. Usando a sintaxe: foreach ( <variable> in <collection> )

foreach ( $node in $data )
{
    "Item: [$node]"
}

Método ForEach

Eu tendo a esquecer este, mas funciona bem para operações simples. O PowerShell permite que você chame .ForEach() uma coleção.

PS> $data.foreach({"Item [$PSItem]"})
Item [Zero]
Item [One]
Item [Two]
Item [Three]

O .foreach() leva um parâmetro que é um bloco de script. Você pode soltar os parênteses e apenas fornecer o bloco de script.

$data.foreach{"Item [$PSItem]"}

Esta é uma sintaxe menos conhecida, mas funciona da mesma forma. Esse foreach método foi adicionado no PowerShell 4.0.

Ciclos For

O for loop é muito usado na maioria dos outros idiomas, mas você não o vê muito no PowerShell. Quando você vê, muitas vezes é no contexto de andar uma matriz.

for ( $index = 0; $index -lt $data.count; $index++)
{
    "Item: [{0}]" -f $data[$index]
}

A primeira coisa que fazemos é inicializar um $index to 0. Em seguida, adicionamos a condição que $index deve ser menor que $data.count. Finalmente, especificamos que toda vez que fazemos loop devemos aumentar o índice em 1. Neste caso $index++ é a abreviatura de $index = $index + 1. O operador de formato (-f) é usado para inserir o valor de na cadeia de caracteres de $data[$index] saída.

Sempre que estiver a utilizar um for loop, preste especial atenção à condição. Eu usei $index -lt $data.count aqui. É fácil errar um pouco a condição para obter um erro na sua lógica. Usar $index -le $data.count ou $index -lt ($data.count - 1) estão sempre um pouco errados. Isso faria com que seu resultado processasse muitos ou poucos itens. Este é o erro clássico off-by-one.

Loop de comutação

Este é um que é fácil de ignorar. Se você fornecer uma matriz para uma instrução switch, ela verificará cada item na matriz.

$data = 'Zero','One','Two','Three'
switch( $data )
{
    'One'
    {
        'Tock'
    }
    'Three'
    {
        'Tock'
    }
    Default
    {
        'Tick'
    }
}
Tick
Tock
Tick
Tock

Há muitas coisas legais que podemos fazer com a instrução switch. Tenho outro artigo dedicado a isso.

Atualização de valores

Quando sua matriz é uma coleção de cadeia de caracteres ou inteiros (tipos de valor), às vezes você pode querer atualizar os valores na matriz à medida que você faz loop sobre eles. A maioria dos loops acima usa uma variável no loop que contém uma cópia do valor. Se você atualizar essa variável, o valor original na matriz não será atualizado.

A exceção a essa afirmação é o for loop. Se você quiser percorrer uma matriz e atualizar valores dentro dela, então o for loop é o que você está procurando.

for ( $index = 0; $index -lt $data.count; $index++ )
{
    $data[$index] = "Item: [{0}]" -f $data[$index]
}

Este exemplo pega um valor por índice, faz algumas alterações e usa esse mesmo índice para atribuí-lo de volta.

Matrizes de objetos

Até agora, a única coisa que colocamos em uma matriz é um tipo de valor, mas as matrizes também podem conter objetos.

$data = @(
    [pscustomobject]@{FirstName='Kevin';LastName='Marquette'}
    [pscustomobject]@{FirstName='John'; LastName='Doe'}
)

Muitos cmdlets retornam coleções de objetos como matrizes quando você os atribui a uma variável.

$processList = Get-Process

Todos os recursos básicos que já falamos ainda se aplicam a matrizes de objetos com alguns detalhes que merecem ser destacados.

Acesso a propriedades

Podemos usar um índice para acessar um item individual em uma coleção, assim como com os tipos de valor.

PS> $data[0]

FirstName LastName
-----     ----
Kevin     Marquette

Podemos acessar e atualizar propriedades diretamente.

PS> $data[0].FirstName

Kevin

PS> $data[0].FirstName = 'Jay'
PS> $data[0]

FirstName LastName
-----     ----
Jay       Marquette

Propriedades da matriz

Normalmente, você teria que enumerar toda a lista assim para acessar todas as propriedades:

PS> $data | ForEach-Object {$_.LastName}

Marquette
Doe

Ou usando o Select-Object -ExpandProperty cmdlet.

PS> $data | Select-Object -ExpandProperty LastName

Marquette
Doe

Mas o PowerShell nos oferece a capacidade de solicitar LastName diretamente. O PowerShell enumera todos eles para nós e retorna uma lista limpa.

PS> $data.LastName

Marquette
Doe

A enumeração ainda acontece, mas não vemos a complexidade por trás dela.

Filtragem Where-Object

É aqui Where-Object que entra para que possamos filtrar e selecionar o que queremos da matriz com base nas propriedades do objeto.

PS> $data | Where-Object {$_.FirstName -eq 'Kevin'}

FirstName LastName
-----     ----
Kevin     Marquette

Podemos escrever essa mesma consulta para obter o que FirstName estamos procurando.

$data | Where FirstName -eq Kevin

Em que()

As matrizes têm um Where() método que permite especificar um scriptblock para o filtro.

$data.Where({$_.FirstName -eq 'Kevin'})

Esse recurso foi adicionado no PowerShell 4.0.

Atualizando objetos em loops

Com tipos de valor, a única maneira de atualizar a matriz é usar um loop for, porque precisamos conhecer o índice para substituir o valor. Temos mais opções com objetos porque são tipos de referência. Aqui está um exemplo rápido:

foreach($person in $data)
{
    $person.FirstName = 'Kevin'
}

Esse loop está andando por todos os objetos da $data matriz. Como os objetos são tipos de referência, a $person variável faz referência exatamente ao mesmo objeto que está na matriz. Portanto, as atualizações de suas propriedades atualizam o original.

Ainda não é possível substituir todo o objeto dessa forma. Se você tentar atribuir um novo objeto à $person variável, estará atualizando a referência da variável para outra coisa que não aponta mais para o objeto original na matriz. Isso não funciona como você esperaria:

foreach($person in $data)
{
    $person = [pscustomobject]@{
        FirstName='Kevin'
        LastName='Marquette'
    }
}

Operadores

Os operadores no PowerShell também trabalham em matrizes. Alguns deles funcionam de forma ligeiramente diferente.

-aderir

O -join operador é o mais óbvio, então vamos olhar para ele primeiro. Eu gosto do -join operador e usá-lo com frequência. Ele une todos os elementos na matriz com o caractere ou cadeia de caracteres que você especificar.

PS> $data = @(1,2,3,4)
PS> $data -join '-'
1-2-3-4
PS> $data -join ','
1,2,3,4

Uma das características que eu gosto sobre o -join operador é que ele lida com itens únicos.

PS> 1 -join '-'
1

Eu uso isso dentro do registro e mensagens detalhadas.

PS> $data = @(1,2,3,4)
PS> "Data is $($data -join ',')."
Data is 1,2,3,4.

-junte-se $array

Aqui está um truque inteligente que Lee Dailey me apontou. Se você quiser juntar tudo sem um delimitador, em vez de fazer isso:

PS> $data = @(1,2,3,4)
PS> $data -join $null
1234

Você pode usar -join com a matriz como o parâmetro sem prefixo. Dê uma olhada neste exemplo para ver que estou falando.

PS> $data = @(1,2,3,4)
PS> -join $data
1234

-substituir e -dividir

Os outros operadores gostam -replace e -split executam em cada item da matriz. Não posso dizer que já os usei desta forma, mas aqui está um exemplo.

PS> $data = @('ATX-SQL-01','ATX-SQL-02','ATX-SQL-03')
PS> $data -replace 'ATX','LAX'
LAX-SQL-01
LAX-SQL-02
LAX-SQL-03

-contém

O -contains operador permite que você verifique uma matriz de valores para ver se ela contém um valor especificado.

PS> $data = @('red','green','blue')
PS> $data -contains 'green'
True

-em

Quando você tem um único valor que você gostaria de verificar corresponde a um dos vários valores, você pode usar o -in operador. O valor estaria à esquerda e a matriz no lado direito do operador.

PS> $data = @('red','green','blue')
PS> 'green' -in $data
True

Isso pode ficar caro se a lista for grande. Eu costumo usar um padrão regex se estou verificando mais do que alguns valores.

PS> $data = @('red','green','blue')
PS> $pattern = "^({0})$" -f ($data -join '|')
PS> $pattern
^(red|green|blue)$

PS> 'green' -match $pattern
True

-eq e -ne

A igualdade e as matrizes podem tornar-se complicadas. Quando a matriz está no lado esquerdo, todos os itens são comparados. Em vez de retornar True, ele retorna o objeto que corresponde.

PS> $data = @('red','green','blue')
PS> $data -eq 'green'
green

Quando você usa o -ne operador, obtemos todos os valores que não são iguais ao nosso valor.

PS> $data = @('red','green','blue')
PS> $data -ne 'green'
red
blue

Quando você usa isso em uma if() instrução, um valor que é retornado é um True valor. Se nenhum valor for retornado, então é um False valor. Ambas as próximas afirmações avaliam a True.

$data = @('red','green','blue')
if ( $data -eq 'green' )
{
    'Green was found'
}
if ( $data -ne 'green' )
{
    'And green was not found'
}

Vou revisitar isso em um momento em que falamos sobre testes para $null.

-jogo

O -match operador tenta corresponder a cada item da coleção.

PS> $servers = @(
    'LAX-SQL-01'
    'LAX-API-01'
    'ATX-SQL-01'
    'ATX-API-01'
)
PS> $servers -match 'SQL'
LAX-SQL-01
ATX-SQL-01

Quando você usa -match com um único valor, uma variável $Matches especial é preenchida com informações de correspondência. Este não é o caso quando uma matriz é processada dessa forma.

Podemos adotar a mesma abordagem com Select-Stringa .

$servers | Select-String SQL

Eu dou uma olhada mais de perto no Select-String, e a $matches variável em outro post chamado As muitas maneiras de usar o regex-match.

$null ou vazio

Testar $null matrizes vazias ou vazias pode ser complicado. Aqui estão as armadilhas comuns com matrizes.

De relance, esta afirmação parece que deve funcionar.

if ( $array -eq $null)
{
    'Array is $null'
}

Mas eu apenas passei por cima de como -eq verifica cada item na matriz. Assim, podemos ter uma matriz de vários itens com um único valor $null e ele avaliaria para $true

$array = @('one',$null,'three')
if ( $array -eq $null)
{
    'I think Array is $null, but I would be wrong'
}

É por isso que é uma boa prática colocar o $null no lado esquerdo do operador. Isso torna esse cenário um não-problema.

if ( $null -eq $array )
{
    'Array actually is $null'
}

Uma $null matriz não é a mesma coisa que uma matriz vazia. Se você sabe que tem uma matriz, verifique a contagem de objetos nela. Se a matriz for $null, a contagem será 0.

if ( $array.count -gt 0 )
{
    "Array isn't empty"
}

Há mais uma armadilha a ter em conta aqui. Você pode usar o count mesmo se tiver um único objeto, a menos que esse objeto seja um PSCustomObjectarquivo . Este é um bug corrigido no PowerShell 6.1. Essa é uma boa notícia, mas muitas pessoas ainda estão na 5.1 e precisam ficar atentas a isso.

PS> $object = [PSCustomObject]@{Name='TestObject'}
PS> $object.count
$null

Se você ainda estiver no PowerShell 5.1, poderá encapsular o objeto em uma matriz antes de verificar a contagem para obter uma contagem precisa.

if ( @($array).count -gt 0 )
{
    "Array isn't empty"
}

Para jogar totalmente seguro, verifique se há $nulle, em seguida, verifique a contagem.

if ( $null -ne $array -and @($array).count -gt 0 )
{
    "Array isn't empty"
}

Todos -eq

Recentemente, vi alguém perguntar como verificar se cada valor em uma matriz corresponde a um determinado valor. O usuário do Reddit /u/bis tinha essa solução inteligente que verifica se há valores incorretos e, em seguida, inverte o resultado.

$results = Test-Something
if ( -not ( $results -ne 'Passed') )
{
    'All results a Passed'
}

Adicionando a matrizes

Neste ponto, você está começando a se perguntar como adicionar itens a uma matriz. A resposta rápida é que não pode. Uma matriz é um tamanho fixo na memória. Se você precisar aumentá-lo ou adicionar um único item a ele, precisará criar uma nova matriz e copiar todos os valores da matriz antiga. Isso parece muito trabalhoso, no entanto, o PowerShell esconde a complexidade da criação da nova matriz. O PowerShell implementa o operador de adição (+) para matrizes.

Nota

O PowerShell não implementa uma operação de subtração. Se você quiser uma alternativa flexível para uma matriz, você precisa usar um objeto genérico List .

Adição de matriz

Podemos usar o operador de adição com matrizes para criar uma nova matriz. Assim, dadas estas duas matrizes:

$first = @(
    'Zero'
    'One'
)
$second = @(
    'Two'
    'Three'
)

Podemos adicioná-los para obter uma nova matriz.

PS> $first + $second

Zero
One
Two
Three

Plus é igual a +=

Podemos criar uma nova matriz no local e adicionar um item a ela assim:

$data = @(
    'Zero'
    'One'
    'Two'
    'Three'
)
$data += 'four'

Lembre-se de que toda vez que você usa += isso, você está duplicando e criando uma nova matriz. Este não é um problema para pequenos conjuntos de dados, mas escala extremamente pobre.

Atribuição de pipeline

Você pode atribuir os resultados de qualquer pipeline em uma variável. É uma matriz se contiver vários itens.

$array = 1..5 | ForEach-Object {
    "ATX-SQL-$PSItem"
}

Normalmente, quando pensamos em usar o pipeline, pensamos nos one-liners típicos do PowerShell. Podemos alavancar o pipeline com foreach() declarações e outros loops. Assim, em vez de adicionar itens a uma matriz em um loop, podemos soltar itens no pipeline.

$array = foreach ( $node in (1..5))
{
    "ATX-SQL-$node"
}

Tipos de matriz

Por padrão, uma matriz no PowerShell é criada como um [PSObject[]] tipo. Isso permite que ele contenha qualquer tipo de objeto ou valor. Isso funciona porque tudo é herdado do PSObject tipo.

Matrizes fortemente tipadas

Você pode criar uma matriz de qualquer tipo usando uma sintaxe semelhante. Quando você cria uma matriz fortemente tipada, ela só pode conter valores ou objetos do tipo especificado.

PS> [int[]] $numbers = 1,2,3
PS> [int[]] $numbers2 = 'one','two','three'
ERROR: Cannot convert value "one" to type "System.Int32". Input string was not in a correct format."

PS> [string[]] $strings = 'one','two','three'

ArrayList

Adicionar itens a uma matriz é uma das suas maiores limitações, mas existem algumas outras coleções às quais podemos recorrer para resolver esse problema.

A ArrayList é geralmente uma das primeiras coisas em que pensamos quando precisamos de uma matriz que seja mais rápida de trabalhar. Ele age como uma matriz de objetos em todos os lugares que precisamos dele, mas lida com a adição de itens rapidamente.

Aqui está como criamos um ArrayList e adicionamos itens a ele.

$myarray = [System.Collections.ArrayList]::new()
[void]$myArray.Add('Value')

Estamos chamando o .NET para obter esse tipo. Neste caso, estamos usando o construtor padrão para criá-lo. Em seguida, chamamos o Add método para adicionar um item a ele.

A razão pela qual estou usando [void] no início da linha é suprimir o código de retorno. Algumas chamadas .NET fazem isso e podem criar uma saída inesperada.

Se os únicos dados que você tem em sua matriz são strings, então também dê uma olhada no uso do StringBuilder. É quase a mesma coisa, mas tem alguns métodos que são apenas para lidar com cordas. O StringBuilder é especialmente projetado para o desempenho.

É comum ver pessoas migrando de ArrayList matrizes. Mas vem de uma época em que o C# não tinha suporte genérico. O ArrayList é preterido no suporte para o genérico List[]

Lista Genérica

Um tipo genérico é um tipo especial em C# que define uma classe generalizada e o usuário especifica os tipos de dados que usa quando criado. Então, se você quiser uma lista de números ou strings, você definiria que você deseja lista de int ou string tipos.

Veja como criar uma lista para cadeias de caracteres.

$mylist = [System.Collections.Generic.List[string]]::new()

Ou uma lista de números.

$mylist = [System.Collections.Generic.List[int]]::new()

Podemos converter uma matriz existente em uma lista como esta sem criar o objeto primeiro:

$mylist = [System.Collections.Generic.List[int]]@(1,2,3)

Podemos encurtar a sintaxe com a using namespace instrução no PowerShell 5 e mais recente. A using instrução precisa ser a primeira linha do seu script. Ao declarar um namespace, o PowerShell permite que você o deixe fora dos tipos de dados quando você os referencia.

using namespace System.Collections.Generic
$myList = [List[int]]@(1,2,3)

Isso torna o List muito mais utilizável.

Você tem um método semelhante Add disponível para você. Ao contrário do ArrayList, não há nenhum valor de retorno no Add método, portanto, não precisamos dele void .

$myList.Add(10)

E ainda podemos acessar os elementos como outras matrizes.

PS> $myList[-1]
10

Lista[PSObject]

Você pode ter uma lista de qualquer tipo, mas quando você não sabe o tipo de objetos, você pode usar [List[PSObject]] para contê-los.

$list = [List[PSObject]]::new()

Remove()

O ArrayList e o genérico List[] suportam a remoção de itens da coleção.

using namespace System.Collections.Generic
$myList = [List[string]]@('Zero','One','Two','Three')
[void]$myList.Remove("Two")
Zero
One
Three

Ao trabalhar com tipos de valor, ele remove o primeiro da lista. Você pode chamá-lo repetidamente para continuar removendo esse valor. Se você tiver tipos de referência, precisará fornecer o objeto que deseja remover.

[list[System.Management.Automation.PSDriveInfo]]$drives = Get-PSDrive
$drives.remove($drives[2])
$delete = $drives[2]
$drives.remove($delete)

O método remove retorna true se foi capaz de localizar e remover o item da coleção.

Mais coleções

Existem muitas outras coleções que podem ser usadas, mas estas são as boas substituições genéricas de matrizes. Se você estiver interessado em saber mais sobre essas opções, dê uma olhada neste Gist que Mark Kraus montou.

Outras nuances

Agora que eu cobri todas as principais funcionalidades, aqui estão mais algumas coisas que eu queria mencionar antes de encerrar isso.

Matrizes pré-dimensionadas

Eu mencionei que você não pode alterar o tamanho de uma matriz depois que ela é criada. Podemos criar uma matriz de um tamanho pré-determinado chamando-a com o new($size) construtor.

$data = [Object[]]::new(4)
$data.count
4

Multiplicando matrizes

Um pequeno truque interessante é que você pode multiplicar uma matriz por um inteiro.

PS> $data = @('red','green','blue')
PS> $data * 3
red
green
blue
red
green
blue
red
green
blue

Inicializar com 0

Um cenário comum é que você deseja criar uma matriz com todos os zeros. Se você tiver apenas números inteiros, uma matriz fortemente tipada de inteiros assumirá como padrão todos os zeros.

PS> [int[]]::new(4)
0
0
0
0

Podemos usar o truque de multiplicação para fazer isso também.

PS> $data = @(0) * 4
PS> $data
0
0
0
0

O bom do truque de multiplicação é que você pode usar qualquer valor. Então, se você preferir ter 255 como seu valor padrão, esta seria uma boa maneira de fazê-lo.

PS> $data = @(255) * 4
PS> $data
255
255
255
255

Matrizes aninhadas

Uma matriz dentro de uma matriz é chamada de matriz aninhada. Eu não os uso muito no PowerShell, mas usei-os mais em outros idiomas. Considere o uso de uma matriz de matrizes quando seus dados se ajustarem a um padrão semelhante a uma grade.

Aqui estão duas maneiras de criar uma matriz bidimensional.

$data = @(@(1,2,3),@(4,5,6),@(7,8,9))

$data2 = @(
    @(1,2,3),
    @(4,5,6),
    @(7,8,9)
)

A vírgula é muito importante nesses exemplos. Eu dei um exemplo anterior de uma matriz normal em várias linhas onde a vírgula era opcional. Esse não é o caso de uma matriz multidimensional.

A maneira como usamos a notação de índice muda ligeiramente agora que temos uma matriz aninhada. Usando o $data acima, é assim que acessamos o valor 3.

PS> $outside = 0
PS> $inside = 2
PS> $data[$outside][$inside]
3

Adicione um conjunto de colchetes para cada nível de aninhamento de matrizes. O primeiro conjunto de suportes é para a matriz mais externa e, em seguida, você trabalha seu caminho a partir daí.

Write-Output -NoEnumerate

O PowerShell gosta de desempacotar ou enumerar matrizes. Esse é um aspeto central da maneira como o PowerShell usa o pipeline, mas há momentos em que você não quer que isso aconteça.

Eu costumo canalizar objetos para Get-Member aprender mais sobre eles. Quando eu canalizo uma matriz para ela, ela é desembrulhada e Get-Member vê os membros da matriz e não a matriz real.

PS> $data = @('red','green','blue')
PS> $data | Get-Member
TypeName: System.String
...

Para evitar que o desembrulho da matriz, você pode usar Write-Output -NoEnumerate.

PS> Write-Output -NoEnumerate $data | Get-Member
TypeName: System.Object[]
...

Eu tenho uma segunda maneira que é mais de um hack (e eu tento evitar hacks como este). Você pode colocar uma vírgula na frente da matriz antes de canalizá-la. Isso se envolve $data em outra matriz onde é o único elemento, então depois de desembrulhar a matriz externa, voltamos $data a ser desembrulhados.

PS> ,$data | Get-Member
TypeName: System.Object[]
...

Retornar uma matriz

Esse desempacotamento de matrizes também acontece quando você produz ou retorna valores de uma função. Você ainda pode obter uma matriz se atribuir a saída a uma variável, portanto, isso não é um problema comum.

O problema é que você tem uma nova matriz. Se isso for um problema, você pode usar Write-Output -NoEnumerate $array ou return ,$array contornar isso.

Mais alguma coisa?

Sei que tudo isto é muito para absorver. Minha esperança é que você aprenda algo com este artigo toda vez que lê-lo e que ele acabe sendo uma boa referência para você por um longo tempo. Se você achou isso útil, por favor, compartilhe-o com outras pessoas que você acha que podem obter valor com isso.

A partir daqui, eu recomendaria que você confira um post semelhante que eu escrevi sobre hashtables.