Arrays do PowerShell, ArrayLists e Coleções: Melhores Práticas

Muitas vezes, ao escrever scripts em PowerShell, você precisa de uma maneira de armazenar um conjunto de itens. Uma maneira comum de fazer isso é com um array ou um tipo específico conhecido como ArrayList. Mas afinal, o que é um array? Um array é uma estrutura de dados projetada para armazenar uma coleção de itens. Isso pode incluir itens do mesmo tipo ou de tipos diferentes.

Arrays são usados em muitas linguagens de programação diferentes, e o PowerShell não é exceção. Existem muitas maneiras de criar, manipular e otimizar arrays. Neste artigo, você aprenderá sobre ArrayLists, Arrays e Coleções, bem como algumas boas práticas ao aplicá-los com o PowerShell.

Pré-requisitos/Requisitos

Como você estará trabalhando apenas com a linguagem PowerShell, não há pré-requisitos ambientais. Você só precisa ter um PC com Windows com PowerShell. Mais especificamente:

  • Windows PowerShell 3 ou posterior
  • .NET Framework 4.5 ou posterior

Quer mais dicas como esta? Confira meu blog pessoal de PowerShell em: https://nkasco.com/FriendsOfATA

Criando Arrays com PowerShell

Existem muitas maneiras diferentes de criar arrays com PowerShell. Vamos supor que você tenha uma lista de nomes que precisa processar de alguma forma, conforme mostrado abaixo.

John
Susie
Jim
Johnny
Carrie

Construindo Arrays via Elementos Separados por Vírgula

A maneira mais básica de criar um array é simplesmente atribuir entradas conhecidas, separadas por vírgulas, a uma variável, conforme mostrado abaixo.

$BasicArray = "John", "Susie", "Jim", "Johnny", "Carrie"

Se você executar o método GetType() disponível em todos os objetos no PowerShell, verá que criou com sucesso um array conforme indicado pela propriedade BaseType mostrada abaixo.

PS51> $BasicArray.GetType()

IsPublic IsSerial Name                                     BaseType                                                    
-------- -------- ----                                     --------                                                    
True     True     Object[]                                 System.Array

Usando o Operador de Subexpressão

Você também pode criar arrays no PowerShell via um operador de subexpressão. Esse conceito é comumente utilizado quando você não sabe quantos itens serão adicionados ao seu array. O resultado pode conter zero ou muitos itens quando criado.

Observe abaixo que um array chamado $MyArray foi criado com zero elementos dentro.

#Criar um array vazio com o operador de subexpressão
PS51> $MyArray = @()
PS51> $MyArray.count
0

Usando o Operador de Intervalo

Arrays não se limitam apenas a armazenar strings como mostrado acima. Você também pode criar arrays com outros tipos de objetos, como inteiros.

Se você precisa de um array de inteiros em ordem sequencial, pode simplificar e usar o operador de intervalo ... Abaixo, você pode ver um array criado com os inteiros de 2 a 5 com uma única linha de código.

PS51> $NumberedArray = 2..5
PS51> $NumberedArray
2
3
4
5

Criando Coleções ArrayList no PowerShell

O uso de um ArrayList no PowerShell é outra forma de armazenar uma lista de itens com o PowerShell. A classe ArrayList faz parte do namespace System.Collections dentro do .NET. Ao criar um novo objeto desse tipo, você pode então armazenar objetos dentro de um ArrayList.

Abaixo, você pode ver que é necessário criar explicitamente um objeto ArrayList usando o cmdlet New-Object ou convertendo um array padrão em um objeto ArrayList.

Observe que neste caso o BaseType é um objeto enquanto os exemplos acima têm BaseTypes de Arrays que exibem herança da classe Object. No final, o PowerShell está fornecendo acesso ao sistema de tipos .NET.

PS51> $MyArrayList = New-Object -TypeName "System.Collections.ArrayList"
# Converter uma matriz em um ArrayList também é uma opção viável
PS51> $MyArrayList = [System.Collections.ArrayList]@()
PS51> $MyArrayList.GetType()

IsPublic IsSerial Name                                     BaseType                                                    
-------- -------- ----                                     --------                                                    
True     True     ArrayList                                System.Object

Adicionando itens a uma matriz

Ao criar uma matriz, você pode definir todos os elementos no momento da criação ou adicioná-los ad hoc.

Para adicionar elementos a uma coleção existente, você pode usar o operador += ou o método Add. Mas saiba que existem diferenças significativas em como eles operam.

Ao criar uma matriz padrão com @(), você usará o operador +=, mas para adicionar elementos a um ArrayList, você usaria o método Add. Esses métodos diferem no sentido de que o operador += na verdade destrói a matriz existente e cria uma nova com o novo item.

Para demonstrar, você verá abaixo que pode fazer referência à propriedade IsFixedSize para uma matriz ou ArrayList para saber qual é imutável e qual não é.

PS51> $BasicArray.IsFixedSize
True

PS51> $MyArrayList.IsFixedSize
False

Já que uma matriz básica é uma coleção de tamanho fixo, você não pode modificá-la.

Tentativa de usar o método Add() com um array de tamanho fixo resultará em um erro devido ao tamanho fixo. Abaixo você pode ver alguns exemplos nos quais você pode adicionar itens a um array.

#Não Funciona
$BasicArray.Add("Nate")

#Funciona
$BasicArray += "Nate"
$MyArrayList.Add("Nate")
$MyArrayList += "Nate"

Removendo Itens de um Array

Agora que você tem uma compreensão melhor de como adicionar itens a um array, vamos cobrir algumas maneiras de remover itens de um array.

Como um array básico é fixo, você não pode remover itens deles. Em vez disso, você precisa criar um novo array completamente. Por exemplo, você pode remover um único elemento de um array criando uma declaração condicional que apenas corresponda aos elementos que você deseja incluir. Um exemplo é mostrado abaixo.

$NewBasicArray = $BasicArray -ne "Nate"

Como um ArrayList não é fixo, você pode remover elementos deles usando o método Remove(). Este é um cenário no qual usar um ArrayList pode beneficiá-lo se você planeja adicionar/remover itens com frequência.

$MyArrayList.Remove("Nate")

Recuperando Itens Específicos de um Array ou ArrayList

Para recuperar itens específicos de um array ou ArrayList, você pode usar muitos métodos diferentes. Assim como outros objetos no PowerShell, você pode acessar todos os elementos de um array simplesmente chamando o objeto.

PS51> $BasicArray
John
Susie
Jim
Johnny
Carrie

Talvez você precise apenas recuperar o primeiro elemento, os arrays sempre terão uma origem de 0 representando o primeiro elemento do array. Para recuperar o primeiro elemento de um array, especifique o número do índice entre colchetes como mostrado abaixo.

PS51> $BasicArray[0]
John

Por outro lado, você também pode fazer referência aos índices de forma inversa usando um traço (indicador negativo) para chamar os últimos X elementos do array. Uma maneira comum de encontrar o último elemento em um array é usar -1, como mostrado abaixo.

PS51> $BasicArray[-1]
Carrie

O operador de intervalo que você aprendeu anteriormente também pode ser usado para recuperar objetos de um array, seguindo o mesmo método de chamada dos elementos. Digamos que você queira recuperar os quatro primeiros nomes no array $BasicArray.

Como pode ser visto abaixo, você pode especificar um intervalo de índices de 0 a 3, o que retornará os quatro primeiros elementos.

PS51> $BasicArray[0..3]
John
Susie
Jim
Johnny

Otimizando Arrays com PowerShell

Agora que você tem uma boa base de como criar e manipular arrays, qual deles você deve usar? Para responder a isso, vamos percorrer alguns exemplos com o cmdlet Measure-Command. Usando o cmdlet Measure-Command, você terá uma melhor compreensão de quanto tempo os comandos estão levando para processar elementos à medida que são passados pelo pipeline.

Em termos gerais, se você tem uma pequena coleção de objetos, provavelmente não notará muita diferença na manipulação de seus arrays. No entanto, se você tem uma grande coleção de objetos, é importante entender as diferenças para obter resultados otimizados.

Vamos aplicar o que você acabou de aprender na seção anterior sobre a diferença entre += e o uso do método Add() com um loop de 50.000 itens.

Primeiro, crie um array vazio e um ArrayList vazio como mostrado abaixo.

PS51> $MyArray = @()
PS51> $MyArrayList = [System.Collections.ArrayList]@()

Em seguida, popule 50.000 elementos em cada coleção usando o operador de intervalo e um loop foreach conforme mostrado abaixo.

@(0..50000).foreach({$MyArray += $_})
@(0..50000).foreach({$MyArrayList.Add($_)})

Por fim, envolva seus comandos em uma expressão e passe essa expressão para o cmdlet Measure-Command. Ao executar a expressão com Measure-Command, você pode ver quanto tempo cada processo realmente leva para ser executado.

Lembre-se de que, como você aprendeu antes, += na verdade cria um novo array em vez de anexar a um fixo.

PS51> Measure-Command -Expression {@(0..50000).foreach({$MyArray += $_})}
Days              : 0
Hours             : 0
Minutes           : 0
Seconds           : 59
Milliseconds      : 58
Ticks             : 590585963
TotalDays         : 0.000683548568287037
TotalHours        : 0.0164051656388889
TotalMinutes      : 0.984309938333333
TotalSeconds      : 59.0585963
TotalMilliseconds : 59058.5963

PS51> Measure-Command -Expression {@(0..50000).foreach({$MyArrayList.Add($_)})}
Days              : 0
Hours             : 0
Minutes           : 0
Seconds           : 0
Milliseconds      : 139
Ticks             : 1399989
TotalDays         : 1.62035763888889E-06
TotalHours        : 3.88885833333333E-05
TotalMinutes      : 0.002333315
TotalSeconds      : 0.1399989
TotalMilliseconds : 139.9989

O resultado? Quase 60 segundos versus 139 milissegundos!

Como você pode ver, é muito mais rápido aproveitar um ArrayList para coleções grandes em vez de usar um array de tamanho fixo.

Embora este seja um exemplo básico, ele destaca a importância de entender o que seu código está fazendo durante o processamento. Se não for devidamente entendido, pode resultar em uma experiência de usuário ruim.

Se você tiver algum script existente que poderia se beneficiar do uso de um ArrayList em vez de um array, esta seria uma oportunidade fantástica para fazer uma melhoria durante a noite!

Leitura adicional

Quer mais dicas como esta? Confira o meu blog pessoal de PowerShell em: https://nkasco.com/FriendsOfATA.

Source:
https://adamtheautomator.com/powershell-array/