Tudo o que queria saber sobre matrizes
As matrizes são uma funcionalidade de linguagem fundamental da maioria das linguagens de programação. São uma coleção de valores ou objetos que são difíceis de evitar. Vamos analisar de perto as matrizes e tudo o que têm para oferecer.
Nota
A versão original deste artigo apareceu no blogue escrito por @KevinMarquette. A equipa do PowerShell agradece ao Kevin por partilhar este conteúdo connosco. Veja o blogue dele no PowerShellExplained.com.
O que é uma matriz?
Vou começar com uma descrição técnica básica sobre o que são matrizes e como são utilizadas pela maioria das linguagens de programação antes de passar para outras formas como o PowerShell as utiliza.
Uma matriz é uma estrutura de dados que serve como uma coleção de múltiplos itens. Pode iterar através da matriz ou aceder a itens individuais através de um índice. A matriz é criada como um segmento sequencial de memória onde cada valor é armazenado mesmo ao lado do outro.
Vou abordar cada um desses detalhes à medida que avançamos.
Utilização básica
Uma vez que as matrizes são uma funcionalidade básica do PowerShell, existe uma sintaxe simples para trabalhar com as mesmas no PowerShell.
Criar uma matriz
Uma matriz vazia pode ser criada com @()
PS> $data = @()
PS> $data.count
0
Podemos criar uma matriz e seedá-la com valores apenas colocando-as @()
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 cadeias, obtemos uma linha por cadeia.
Podemos declarar uma matriz em várias linhas. A vírgula é opcional neste caso e geralmente deixada de fora.
$data = @(
'Zero'
'One'
'Two'
'Three'
)
Prefiro declarar as minhas matrizes em várias linhas como esta. Não só é mais fácil de ler quando tem múltiplos itens, como também facilita a comparação com versões anteriores ao utilizar o controlo de origem.
Outra sintaxe
Normalmente, entende-se que @()
é a sintaxe para criar uma matriz, mas as listas separadas por vírgulas funcionam na maioria das vezes.
$data = 'Zero','One','Two','Three'
Write-Output para criar matrizes
Um truque interessante que vale a pena mencionar é que pode utilizar Write-Output
para criar rapidamente cadeias de carateres na consola do .
$data = Write-Output Zero One Two Three
Isto é útil porque não tem de colocar aspas à volta das cadeias quando o parâmetro aceita cadeias. Nunca faria isto num guião, mas é um jogo justo na consola.
Aceder a itens
Agora que tem uma matriz com itens, poderá querer aceder e atualizar esses itens.
Desvio
Para aceder a itens individuais, utilizamos os parênteses []
retos com um valor de deslocamento a partir de 0. É assim que obtemos o primeiro item na nossa matriz:
PS> $data = 'Zero','One','Two','Three'
PS> $data[0]
Zero
A razão pela qual utilizamos zero aqui é porque o primeiro item está no início da lista, pelo que utilizamos um desvio de 0 itens para aceder ao mesmo. Para chegar ao segundo item, teríamos de utilizar um desvio de 1 para ignorar o primeiro item.
PS> $data[1]
One
Isto significaria que o último item está no desvio 3.
PS> $data[3]
Three
Índice
Agora pode ver por que escolhi os valores que fiz para este exemplo. Apresentei-o como um desvio, porque é isso que realmente é, mas este desvio é mais frequentemente referido como um índice. Um índice que começa em 0
. Para o resto deste artigo, vou chamar o desvio de um índice.
Truques especiais do índice
Na maioria dos idiomas, só pode especificar um único número como índice e obter um único item de volta. O PowerShell é muito mais flexível. Pode utilizar 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 devolvidos com base na ordem dos índices fornecidos. Se duplicar um índice, obterá esse item em ambas as ocasiões.
PS> $data[3,0,3]
Three
Zero
Three
Podemos especificar uma sequência de números com o operador incorporado ..
.
PS> $data[1..3]
One
Two
Three
Isto também funciona ao contrário.
PS> $data[3..1]
Three
Two
One
Pode utilizar valores de índice negativos para compensar a partir do fim. Por isso, se precisar do último item na lista, pode utilizar -1
.
PS> $data[-1]
Three
Uma palavra de cuidado aqui com o ..
operador. A sequência 0..-1
e -1..0
avalia os valores 0,-1
e -1,0
. É fácil ver $data[0..-1]
e pensar que enumeraria todos os itens se se esquecesse deste detalhe. $data[0..-1]
dá-lhe o mesmo valor $data[0,-1]
que ao dar-lhe o primeiro e último item na matriz (e nenhum dos outros valores). Eis 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 tentar aceder a um índice de um item que ultrapassou o fim da matriz, obterá algum tipo de erro ou uma exceção. O PowerShell devolve automaticamente nada.
PS> $null -eq $data[9000]
True
Não é possível indexar numa matriz nula
Se a variável for $null
e tentar indexá-la como uma matriz, obtém 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.
Por isso, certifique-se de que as matrizes não $null
estão antes de tentar aceder aos elementos dentro das mesmas.
de palavras
As matrizes e outras coleções têm uma propriedade count que indica quantos itens estão na matriz.
PS> $data.count
4
O PowerShell 3.0 adicionou uma propriedade count à maioria dos objetos. pode ter um único objeto e deve dar-lhe uma contagem de 1
.
PS> $date = Get-Date
PS> $date.count
1
Até $null
tem uma propriedade de contagem, exceto que devolve 0
.
PS> $null.count
0
Há aqui algumas armadilhas que vou revisitar quando cobrir matrizes à procura $null
ou vazias mais adiante neste artigo.
Erros off-by-one
É criado um erro de programação comum porque as matrizes começam no índice 0. Os erros off-by-one podem ser introduzidos de duas formas.
A primeira é pensar mentalmente que quer o segundo item e utilizar um índice de 2
e obter realmente o terceiro item. Em alternativa, ao pensar que tem quatro itens e pretende o último item, utilize a contagem para aceder ao último item.
$data[ $data.count ]
O PowerShell tem todo o gosto em permitir-lhe fazê-lo e dar-lhe exatamente o item que existe no índice 4: $null
. Deve utilizar $data.count - 1
ou o -1
que aprendemos acima.
PS> $data[ $data.count - 1 ]
Three
É aqui que pode utilizar 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 de índice.
PS> $data.GetUpperBound(0)
3
PS> $data[ $data.GetUpperBound(0) ]
Three
A segunda forma mais comum é ao iterar a lista e não parar no momento certo. Vou rever isto quando falarmos sobre como utilizar o for
ciclo.
A atualizar itens
Podemos utilizar o mesmo índice para atualizar itens existentes na matriz. Isto dá-nos acesso direto para atualizar itens individuais.
$data[2] = 'dos'
$data[3] = 'tres'
Se tentarmos atualizar um item que ultrapassou o ú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
Vou rever isto mais tarde quando falar sobre como aumentar uma matriz.
Iteração
A dada altura, poderá ter de andar ou iterar toda a lista e efetuar alguma ação para cada item na matriz.
Pipeline
As matrizes e o pipeline do PowerShell destinam-se entre si. Esta é uma das formas mais simples de processar sobre esses valores. Quando transmite 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 nunca viu $PSItem
antes, saiba que é a mesma coisa $_
que . Pode utilizar qualquer um deles porque ambos representam o objeto atual no pipeline.
Ciclo ForEach
O ForEach
ciclo funciona bem com coleções. Com a sintaxe: foreach ( <variable> in <collection> )
foreach ( $node in $data )
{
"Item: [$node]"
}
ForEach method (Método ForEach)
Eu tendo a esquecer este, mas funciona bem para operações simples. O PowerShell permite-lhe chamar .ForEach()
numa coleção.
PS> $data.foreach({"Item [$PSItem]"})
Item [Zero]
Item [One]
Item [Two]
Item [Three]
O .foreach()
utiliza um parâmetro que é um bloco de script. Pode remover os parênteses e apenas fornecer o bloco de script.
$data.foreach{"Item [$PSItem]"}
Esta é uma sintaxe menos conhecida, mas funciona da mesma forma. Este foreach
método foi adicionado ao PowerShell 4.0.
Ciclos For
O for
ciclo é muito utilizado na maioria dos outros idiomas, mas não o vê muito no PowerShell. Quando o vê, é frequentemente no contexto de caminhar numa matriz.
for ( $index = 0; $index -lt $data.count; $index++)
{
"Item: [{0}]" -f $data[$index]
}
A primeira coisa que fazemos é inicializar um $index
para 0
. Em seguida, adicionamos a condição que $index
tem de ser inferior a $data.count
. Por fim, especificamos que sempre que repetirmos o ciclo, tenho de aumentar o índice em 1
. Neste caso, $index++
é abreviatura de $index = $index + 1
. O operador de formato (-f
) é utilizado para inserir o valor de na cadeia de $data[$index]
saída.
Sempre que estiver a utilizar um for
ciclo, preste especial atenção à condição. $index -lt $data.count
Usei aqui. É fácil fazer com que a condição fique ligeiramente errada para obter um erro off-by-one na sua lógica. Utilizar $index -le $data.count
ou $index -lt ($data.count - 1)
alguma vez estiver um pouco errado. Isso faria com que o resultado processasse demasiados ou poucos itens. Este é o erro clássico off-by-one.
Alternar ciclo
Este é um que é fácil de ignorar. Se fornecer uma matriz a uma instrução switch, esta verifica cada item na matriz.
$data = 'Zero','One','Two','Three'
switch( $data )
{
'One'
{
'Tock'
}
'Three'
{
'Tock'
}
Default
{
'Tick'
}
}
Tick
Tock
Tick
Tock
Há muitas coisas interessantes que podemos fazer com a instrução switch. Tenho outro artigo dedicado a isto.
A atualizar valores
Quando a matriz é uma coleção de cadeias ou números inteiros (tipos de valor), por vezes poderá querer atualizar os valores na matriz à medida que percorre os mesmos. A maioria dos ciclos acima utiliza uma variável no ciclo que contém uma cópia do valor. Se atualizar essa variável, o valor original na matriz não será atualizado.
A exceção a essa instrução é o for
ciclo. Se quiser percorrer uma matriz e atualizar os valores dentro da mesma, o for
ciclo é o que procura.
for ( $index = 0; $index -lt $data.count; $index++ )
{
$data[$index] = "Item: [{0}]" -f $data[$index]
}
Este exemplo utiliza um valor por índice, faz algumas alterações e, em seguida, utiliza esse mesmo índice para o atribuir novamente.
Matrizes de Objetos
Até agora, a única coisa que colocámos numa 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 devolvem coleções de objetos como matrizes quando os atribui a uma variável.
$processList = Get-Process
Todas as funcionalidades básicas de que já falámos ainda se aplicam a matrizes de objetos com alguns detalhes que vale a pena destacar.
Aceder às propriedades
Podemos utilizar um índice para aceder a um item individual numa coleção, tal como acontece com tipos de valor.
PS> $data[0]
FirstName LastName
----- ----
Kevin Marquette
Podemos aceder e atualizar as propriedades diretamente.
PS> $data[0].FirstName
Kevin
PS> $data[0].FirstName = 'Jay'
PS> $data[0]
FirstName LastName
----- ----
Jay Marquette
Propriedades da matriz
Normalmente, teria de enumerar toda a lista desta forma para aceder a todas as propriedades:
PS> $data | ForEach-Object {$_.LastName}
Marquette
Doe
Ou através do Select-Object -ExpandProperty
cmdlet .
PS> $data | Select-Object -ExpandProperty LastName
Marquette
Doe
Mas o PowerShell oferece-nos a capacidade de pedir LastName
diretamente. O PowerShell enumera-os todos por nós e devolve uma lista limpa.
PS> $data.LastName
Marquette
Doe
A enumeração ainda acontece, mas não vemos a complexidade por trás da mesma.
filtragem de Where-Object
É aqui que Where-Object
entra para podermos 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 FirstName
que procuramos.
$data | Where FirstName -eq Kevin
Onde()
As matrizes têm um Where()
método que lhe permite especificar um scriptblock
para o filtro.
$data.Where({$_.FirstName -eq 'Kevin'})
Esta funcionalidade foi adicionada ao PowerShell 4.0.
Atualizar objetos em ciclos
Com os tipos de valor, a única forma de atualizar a matriz é utilizar um ciclo for porque precisamos de saber o índice para substituir o valor. Temos mais opções com objetos porque são tipos de referência. Eis um exemplo rápido:
foreach($person in $data)
{
$person.FirstName = 'Kevin'
}
Este ciclo está a percorrer todos os objetos na $data
matriz. Uma vez que os objetos são tipos de referência, a $person
variável referencia exatamente o mesmo objeto que está na matriz. Assim, as atualizações às respetivas propriedades atualizam o original.
Ainda assim, não pode substituir todo o objeto desta forma. Se tentar atribuir um novo objeto à $person
variável, está a atualizar a referência de variável para outra coisa que já não aponta para o objeto original na matriz. Isto não funciona como seria de esperar:
foreach($person in $data)
{
$person = [pscustomobject]@{
FirstName='Kevin'
LastName='Marquette'
}
}
Operadores
Os operadores no PowerShell também funcionam em matrizes. Alguns deles funcionam de forma ligeiramente diferente.
-join
O -join
operador é o mais óbvio, por isso vamos vê-lo primeiro. Gosto do operador e uso-o -join
com frequência. Associa todos os elementos na matriz ao caráter ou cadeia que especificar.
PS> $data = @(1,2,3,4)
PS> $data -join '-'
1-2-3-4
PS> $data -join ','
1,2,3,4
Uma das funcionalidades de que gosto no -join
operador é que processa itens únicos.
PS> 1 -join '-'
1
Utilizo isto dentro de registos e mensagens verbosas.
PS> $data = @(1,2,3,4)
PS> "Data is $($data -join ',')."
Data is 1,2,3,4.
-join $array
Aqui está um truque inteligente que Lee Dailey me apontou. Se alguma vez quiser associar tudo sem um delimitador, em vez de fazer isto:
PS> $data = @(1,2,3,4)
PS> $data -join $null
1234
Pode utilizar -join
com a matriz como o parâmetro sem prefixo. Veja este exemplo para ver de que estou a falar.
PS> $data = @(1,2,3,4)
PS> -join $data
1234
-substituir e -dividir
Os outros operadores gostam -replace
e -split
executam em cada item na 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-lhe verificar uma matriz de valores para ver se contém um valor especificado.
PS> $data = @('red','green','blue')
PS> $data -contains 'green'
True
-in
Quando tiver um único valor que gostaria de verificar corresponde a um de vários valores, pode utilizar o -in
operador . O valor seria à esquerda e a matriz no lado direito do operador.
PS> $data = @('red','green','blue')
PS> 'green' -in $data
True
Isto pode ficar caro se a lista for grande. Utilizo frequentemente um padrão regex se estiver a verificar 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 ficar complicadas. Quando a matriz está no lado esquerdo, cada item é comparado. Em vez de devolver True
, devolve o objeto correspondente.
PS> $data = @('red','green','blue')
PS> $data -eq 'green'
green
Quando utiliza 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 utiliza isto numa instrução if()
, um valor devolvido é um True
valor. Se não for devolvido nenhum valor, será um False
valor. Ambas as instruções seguintes são avaliadas como True
.
$data = @('red','green','blue')
if ( $data -eq 'green' )
{
'Green was found'
}
if ( $data -ne 'green' )
{
'And green was not found'
}
Vou rever isto num momento em que falamos sobre testes para $null
.
-match
O -match
operador tenta corresponder a cada item na 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 utiliza -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 desta forma.
Podemos seguir a mesma abordagem com Select-String
.
$servers | Select-String SQL
Dou uma vista de olhos Select-String
-match
mais detalhadamente e a $matches
variável noutra publicação denominada As muitas formas de utilizar o regex.
$null ou vazio
$null
Testar matrizes vazias ou pode ser complicado. Eis as armadilhas comuns com matrizes.
De relance, esta instrução parece que deve funcionar.
if ( $array -eq $null)
{
'Array is $null'
}
Mas acabei de ver como -eq
verifica cada item na matriz. Assim, podemos ter uma matriz de vários itens com um único valor de $null e seria avaliada como $true
$array = @('one',$null,'three')
if ( $array -eq $null)
{
'I think Array is $null, but I would be wrong'
}
É por isso que é uma melhor prática colocar o $null
no lado esquerdo do operador. Isto faz com que este cenário não seja um problema.
if ( $null -eq $array )
{
'Array actually is $null'
}
Uma $null
matriz não é a mesma coisa que uma matriz vazia. Se souber que tem uma matriz, verifique a contagem de objetos na mesma. Se a matriz for $null
, a contagem é 0
.
if ( $array.count -gt 0 )
{
"Array isn't empty"
}
Há mais uma armadilha para watch por aqui. Pode utilizar o count
mesmo se tiver um único objeto, a menos que esse objeto seja um PSCustomObject
. Este é um erro corrigido no PowerShell 6.1.
São boas notícias, mas muitas pessoas ainda estão no 5.1 e precisam de watch por isso.
PS> $object = [PSCustomObject]@{Name='TestObject'}
PS> $object.count
$null
Se ainda estiver no PowerShell 5.1, pode moldar o objeto numa matriz antes de verificar a contagem para obter uma contagem precisa.
if ( @($array).count -gt 0 )
{
"Array isn't empty"
}
Para o jogar totalmente seguro, verifique $null
se existe e, em seguida, verifique a contagem.
if ( $null -ne $array -and @($array).count -gt 0 )
{
"Array isn't empty"
}
Tudo -eq
Vi recentemente alguém perguntar como verificar se cada valor numa matriz corresponde a um determinado valor. O utilizador /u/bis do Reddit tinha esta solução inteligente que verifica se existem valores incorretos e, em seguida, inverte o resultado.
$results = Test-Something
if ( -not ( $results -ne 'Passed') )
{
'All results a Passed'
}
Adicionar a matrizes
Neste momento, começa a perguntar-se como adicionar itens a uma matriz. A resposta rápida é que não pode. Uma matriz é um tamanho fixo na memória. Se precisar de o aumentar ou adicionar um único item, terá de criar uma nova matriz e copiar todos os valores da matriz antiga. No entanto, parece muito trabalho, o PowerShell oculta 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 quiser uma alternativa flexível a uma matriz, tem de utilizar um objeto genérico List
.
Adição de matriz
Podemos utilizar o operador de adição com matrizes para criar uma nova matriz. Assim, tendo em conta estas duas matrizes:
$first = @(
'Zero'
'One'
)
$second = @(
'Two'
'Three'
)
Podemos adicioná-los para obter uma nova matriz.
PS> $first + $second
Zero
One
Two
Three
Mais é igual a +=
Podemos criar uma nova matriz no local e adicionar-lhe um item da seguinte forma:
$data = @(
'Zero'
'One'
'Two'
'Three'
)
$data += 'four'
Lembre-se de que sempre que utiliza +=
está a duplicar e a criar uma nova matriz. Este não é um problema para pequenos conjuntos de dados, mas dimensiona muito mal.
Atribuição de pipeline
Pode atribuir os resultados de qualquer pipeline a uma variável. É uma matriz se contiver vários itens.
$array = 1..5 | ForEach-Object {
"ATX-SQL-$PSItem"
}
Normalmente, quando pensamos em utilizar o pipeline, pensamos nos liners únicos típicos do PowerShell. Podemos tirar partido do pipeline com foreach()
instruções e outros ciclos. Assim, em vez de adicionar itens a uma matriz num ciclo, podemos largar itens no pipeline.
$array = foreach ( $node in (1..5))
{
"ATX-SQL-$node"
}
Tipos de Matriz
Por predefinição, é criada uma matriz no PowerShell como um [PSObject[]]
tipo. Isto permite-lhe conter qualquer tipo de objeto ou valor. Isto funciona porque tudo é herdado do PSObject
tipo .
Matrizes com tipos fortes
Pode criar uma matriz de qualquer tipo com uma sintaxe semelhante. Quando cria uma matriz fortemente escrita, esta 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 que podemos recorrer para resolver este problema.
Normalmente ArrayList
, é uma das primeiras coisas em que pensamos quando precisamos de uma matriz mais rápida para trabalhar. Funciona como uma matriz de objetos em todos os pontos de que precisamos, mas processa a adição de itens rapidamente.
Eis como criamos um ArrayList
e adicionamos itens ao mesmo.
$myarray = [System.Collections.ArrayList]::new()
[void]$myArray.Add('Value')
Estamos a chamar o .NET para obter este tipo. Neste caso, estamos a utilizar o construtor predefinido para criá-lo. Em seguida, chamamos o Add
método para adicionar um item ao mesmo.
A razão pela qual estou a utilizar [void]
no início da linha é para suprimir o código de retorno. Algumas chamadas .NET fazem-no e podem criar uma saída inesperada.
Se os únicos dados que tem na sua matriz forem as cadeias, veja também a utilização do StringBuilder. É quase a mesma coisa, mas tem alguns métodos que são apenas para lidar com cadeias. O StringBuilder
foi concebido especialmente para desempenho.
É comum ver as pessoas moverem-se de ArrayList
matrizes. Mas vem de uma época em que o C# não tinha suporte genérico. O ArrayList
foi 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 utilizador especifica os tipos de dados que utiliza quando é criado. Por isso, se quiser uma lista de números ou cadeias, definirá que pretende lista ou int
string
tipos.
Eis como criar uma Lista para cadeias de carateres.
$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 numa lista como esta sem criar primeiro o objeto:
$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 tem de ser a primeira linha do script. Ao declarar um espaço de nomes, o PowerShell permite-lhe deixá-lo de fora dos tipos de dados quando os referenciar.
using namespace System.Collections.Generic
$myList = [List[int]]@(1,2,3)
Isto torna o List
muito mais utilizável.
Tem um método semelhante Add
disponível para si. Ao contrário da ArrayList, não existe nenhum valor devolvido no Add
método, pelo que não temos de o fazer void
.
$myList.Add(10)
E ainda podemos aceder aos elementos, como outras matrizes.
PS> $myList[-1]
10
List[PSObject]
Pode ter uma lista de qualquer tipo, mas quando não sabe o tipo de objetos, pode utilizá-los [List[PSObject]]
para os conter.
$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, remove o primeiro da lista. Pode chamá-lo repetidamente para continuar a remover esse valor. Se tiver tipos de referência, tem de fornecer o objeto que pretende remover.
[list[System.Management.Automation.PSDriveInfo]]$drives = Get-PSDrive
$drives.remove($drives[2])
$delete = $drives[2]
$drives.remove($delete)
O método remove devolve true
se conseguiu localizar e remover o item da coleção.
Mais coleções
Existem muitas outras coleções que podem ser utilizadas, mas estas são as boas substituições de matriz genéricas. Se estiver interessado em aprender mais sobre estas opções, veja este Gist que Mark Kraus juntou.
Outras nuances
Agora que abordei todas as principais funcionalidades, eis mais algumas coisas que queria mencionar antes de terminar isto.
Matrizes pré-dimensionadas
Mencionei que não pode alterar o tamanho de uma matriz depois de ser criada. Podemos criar uma matriz de um tamanho pré-determinado ao chamá-la com o new($size)
construtor.
$data = [Object[]]::new(4)
$data.count
4
Multiplicar matrizes
Um truque interessante é que pode multiplicar uma matriz por um número 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 pretende criar uma matriz com todos os zeros. Se apenas tiver números inteiros, uma matriz de números inteiros fortemente digitada é predefinida para todos os zeros.
PS> [int[]]::new(4)
0
0
0
0
Também podemos utilizar o truque de multiplicação para o fazer.
PS> $data = @(0) * 4
PS> $data
0
0
0
0
O bom do truque de multiplicação é que pode usar qualquer valor. Por isso, se preferir ter 255
como valor predefinido, esta seria uma boa forma de o fazer.
PS> $data = @(255) * 4
PS> $data
255
255
255
255
Matrizes aninhadas
Uma matriz dentro de uma matriz é denominada matriz aninhada. Não utilizo estes elementos no PowerShell, mas já os usei mais noutras linguagens. Considere utilizar uma matriz de matrizes quando os seus dados se enquadram numa grelha como o padrão.
Eis duas formas 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. Dei um exemplo anterior de uma matriz normal em múltiplas linhas em que a vírgula era opcional. Não é o caso de uma matriz multidimensional.
A forma como utilizamos a notação de índice muda ligeiramente agora que temos uma matriz aninhada. Com o $data
acima, é assim que acederíamos ao valor 3.
PS> $outside = 0
PS> $inside = 2
PS> $data[$outside][$inside]
3
Adicione um conjunto de parênteses retos para cada nível de aninhamento de matriz. O primeiro conjunto de parênteses retos destina-se à matriz mais externa e, em seguida, pode entrar a partir daí.
Write-Output -NoEnumerate
O PowerShell gosta de desembrulhar ou enumerar matrizes. Este é um aspeto fundamental da forma como o PowerShell utiliza o pipeline, mas há alturas em que não quer que isso aconteça.
Normalmente, encaminho objetos para Get-Member
saber mais sobre eles. Quando encaminho uma matriz para a mesma, esta é 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 impedir que a matriz seja desembrulhada, pode utilizar Write-Output -NoEnumerate
.
PS> Write-Output -NoEnumerate $data | Get-Member
TypeName: System.Object[]
...
Tenho uma segunda maneira que é mais um hack (e tento evitar hacks como este). Pode colocar uma vírgula à frente da matriz antes de a encaminhar. Esta ação é moldada noutra matriz onde é o único elemento, pelo que, após a desembrulhação $data
da matriz externa, voltamos $data
a ser desembrulhados.
PS> ,$data | Get-Member
TypeName: System.Object[]
...
Devolver uma matriz
Esta anulação da substituição de matrizes também ocorre quando devolve valores de uma função. Ainda pode obter uma matriz se atribuir o resultado a uma variável, pelo que este não é normalmente um problema.
O problema é que tem uma nova matriz. Se isso for um problema, pode utilizar Write-Output -NoEnumerate $array
ou return ,$array
contornar o problema.
Mais alguma coisa?
Sei que isto é tudo muito para aceitar. A minha esperança é que aprendas algo com este artigo sempre que o lês e que se revele uma boa referência para ti durante muito tempo. Se considerou isto útil, partilhe-o com outras pessoas que considere que podem obter valor.
A partir daqui, recomendaria que verificasse uma publicação semelhante que escrevi sobre tabelas hash.