Arreglos de PowerShell, ArrayLists y Colecciones: Mejores Prácticas

A menudo, al escribir scripts en PowerShell, necesitas una forma de almacenar un conjunto de elementos. Una manera común de lograr esto es mediante un array o un tipo específico conocido como ArrayList. Pero, ¿qué es un array en realidad? Un array es una estructura de datos diseñada para almacenar una colección de elementos. Esto puede incluir elementos del mismo tipo o de tipos diferentes.

Los arrays se utilizan en muchos lenguajes de programación diferentes, y PowerShell no es una excepción. Hay muchas formas de crear, manipular y optimizar arrays. En este artículo, aprenderás sobre ArrayLists, Arrays y Colecciones, así como algunas mejores prácticas al aplicarlos en PowerShell.

Prerrequisitos/Requisitos

Dado que trabajarás únicamente con el lenguaje PowerShell, no hay requisitos ambientales. Solo necesitas tener una PC con Windows y PowerShell. Más específicamente:

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

¿Quieres más consejos como este? Visita mi blog personal de PowerShell en: https://nkasco.com/FriendsOfATA

Creando Arrays con PowerShell

Existen diversas formas de crear arrays con PowerShell. Supongamos que tienes una lista de nombres que necesitas procesar de alguna manera, como se muestra a continuación.

John
Susie
Jim
Johnny
Carrie

Construyendo Arrays mediante Elementos Separados por Comas

La forma más básica de crear un array es asignar entradas conocidas, separadas por comas, a una variable, como se muestra a continuación.

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

Si ejecutas el método GetType() disponible en todos los objetos en PowerShell, verás que has creado correctamente un array, como indica la propiedad BaseType que se muestra a continuación.

PS51> $BasicArray.GetType()

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

Utilizando el Operador de Subexpresión

También puedes crear arrays en PowerShell mediante un operador de subexpresión. Este concepto se utiliza comúnmente cuando no sabes cuántos elementos se agregarán a tu array. El resultado puede contener cero o muchos elementos al crearse.

Observa a continuación que se ha creado un array llamado $MyArray sin elementos dentro.

#Crear un array vacío con el operador de subexpresión
PS51> $MyArray = @()
PS51> $MyArray.count
0

Usando el Operador de Rango

Los arrays no están limitados solo a almacenar cadenas, como se muestra anteriormente. También puedes crear arrays con otros tipos de objetos como enteros.

Si necesitas un array de enteros en orden secuencial, puedes usar el atajo del rango con el operador ... A continuación, puedes ver que se creó un array con los enteros del 2 al 5 con una sola línea de código.

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

Creación de Colecciones de ArrayList en PowerShell

Usar un ArrayList en PowerShell es otra forma de almacenar una lista de elementos con PowerShell. La clase ArrayList forma parte del espacio de nombres System.Collections en .NET. Al crear un nuevo objeto de este tipo, puedes almacenar objetos dentro de un ArrayList.

A continuación, puedes ver que necesitas crear explícitamente un objeto ArrayList utilizando el cmdlet New-Object o convirtiendo un array estándar en un objeto ArrayList.

Observa que en este caso, el BaseType es un objeto, mientras que los ejemplos anteriores tienen BaseTypes de Arrays, los cuales muestran herencia de la clase Object. En última instancia, PowerShell proporciona acceso al sistema de tipos de .NET.

PS51> $MyArrayList = New-Object -TypeName "System.Collections.ArrayList"
# Convertir una matriz en un ArrayList también es una opción viable
PS51> $MyArrayList = [System.Collections.ArrayList]@()
PS51> $MyArrayList.GetType()

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

Agregar elementos a una matriz

Al crear una matriz, puedes definir todos los elementos en el momento de la creación o agregarlos según sea necesario.

Para agregar elementos a una colección existente, puedes usar el operador += o el método Add. Pero ten en cuenta que hay diferencias importantes en la forma en que operan.

Cuando creas una matriz estándar con @(), usarás el operador +=, pero para agregar elementos a un ArrayList, usarías el método Add. Estos métodos difieren en que el operador += en realidad destruye la matriz existente y crea una nueva con el nuevo elemento.

Para demostrarlo, verás que puedes hacer referencia a la propiedad IsFixedSize de una matriz o ArrayList para saber cuál es inmutable y cuál no lo es.

PS51> $BasicArray.IsFixedSize
True

PS51> $MyArrayList.IsFixedSize
False

Dado que una matriz básica es una colección de tamaño fijo, no puedes modificarla.

Intentar utilizar el método Add() con una matriz de tamaño fijo resultará en un error debido al tamaño fijo. A continuación, puedes ver algunos ejemplos en los que puedes agregar elementos a una matriz.

#No funciona
$BasicArray.Add("Nate")

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

Eliminación de elementos de una matriz

Ahora que tienes una mejor comprensión de cómo agregar elementos a una matriz, cubramos algunas formas en las que puedes eliminar elementos de una matriz.

Dado que una matriz básica es fija, no puedes eliminar elementos de ellas. En su lugar, tienes que crear una matriz completamente nueva. Por ejemplo, puedes eliminar un solo elemento de una matriz creando una declaración condicional que solo coincida con los elementos que desees incluir. Se muestra un ejemplo a continuación.

$NewBasicArray = $BasicArray -ne "Nate"

Dado que un ArrayList no es fijo, puedes eliminar elementos de ellos usando el método Remove(). Este es un escenario en el que el uso de un ArrayList puede beneficiarte si planeas agregar/eliminar elementos con frecuencia.

$MyArrayList.Remove("Nate")

Recuperación de elementos específicos de una matriz o ArrayList

Para recuperar elementos específicos de una matriz o ArrayList, puedes usar muchos métodos diferentes. Al igual que con otros objetos en PowerShell, puedes acceder a todos los elementos de una matriz simplemente llamando al objeto.

PS51> $BasicArray
John
Susie
Jim
Johnny
Carrie

Tal vez necesites recuperar solo el primer elemento, las matrices siempre tendrán un origen de 0 que representa el primer elemento de la matriz. Para recuperar el primer elemento de una matriz, especifica el número de índice entre corchetes como se muestra a continuación.

PS51> $BasicArray[0]
John

Por el contrario, también puedes hacer referencia a índices hacia atrás usando un guión (indicador negativo) para llamar a los últimos X elementos del array. Una forma común de encontrar el último elemento en un array es usando -1 como se muestra a continuación.

PS51> $BasicArray[-1]
Carrie

El operador de rango que aprendiste anteriormente también se puede usar para recuperar objetos de un array siguiendo el mismo método de llamar a los elementos. Digamos que quieres recuperar los primeros cuatro nombres en el array $BasicArray.

Puedes ver a continuación que puedes especificar un rango de índices 0-3 que devolverá los primeros cuatro elementos.

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

Optimizando Arrays con PowerShell

Ahora que tienes una buena base de cómo crear y manipular arrays, ¿cuál deberías usar? Para responder a eso, recorramos algunos ejemplos con el cmdlet Measure-Command. Usando el cmdlet Measure-Command, comprenderás mejor cuánto tiempo tardan los comandos en procesar elementos a medida que se pasan por el pipeline.

En general, si tienes una pequeña colección de objetos, es probable que no notes mucha diferencia en cómo manipulas tus arrays. Sin embargo, si tienes una gran colección de objetos, es importante entender las diferencias para lograr resultados óptimos.

Aplica lo que acabas de aprender en la sección anterior sobre la diferencia entre += y el uso del método Add() con un bucle de 50,000 elementos.

Primero, crea un array vacío y un ArrayList vacío como se muestra a continuación.

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

Luego, poblamos 50,000 elementos en cada colección usando el operador de rango y un bucle foreach como se muestra a continuación.

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

Finalmente, envuelve tus comandos en una expresión y pasa esa expresión al cmdlet Measure-Command. Al ejecutar la expresión con Measure-Command, puedes ver cuánto tiempo realmente tarda en ejecutarse cada proceso.

Ten en cuenta que, como aprendiste antes, += realmente crea un nuevo array en lugar de agregar a uno fijo.

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

¿El resultado? ¡Casi 60 segundos frente a 139 milisegundos!

Como puedes ver, es mucho más rápido aprovechar un ArrayList para colecciones grandes en lugar de usar un array de tamaño fijo.

Si bien este es un ejemplo básico, subraya la importancia de entender lo que está haciendo tu código durante el procesamiento. Si no se entiende correctamente, puede resultar en una mala experiencia para el usuario.

¡Si tienes algún script existente que podría beneficiarse de usar un ArrayList en lugar de un array, esta sería una oportunidad fantástica para realizar una mejora de la noche a la mañana!

Lectura adicional

¿Quieres más consejos como este? Visita mi blog personal de PowerShell en: https://nkasco.com/FriendsOfATA.

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