Todo lo que le interesa sobre las matrices
Las matrices son una característica de lenguaje fundamental de la mayoría de los lenguajes de programación. Son una colección de valores u objetos que son difíciles de evitar. Vamos a profundizar en las matrices y en todo lo que tienen que ofrecer.
Nota
La versión original de este artículo apareció en el blog escrito por @KevinMarquette. El equipo de PowerShell agradece a Kevin que comparta este contenido con nosotros. Visite su blog en PowerShellExplained.com.
¿Qué es una matriz?
Voy a empezar con una descripción técnica básica sobre qué son las matrices y cómo se usan en la mayoría de los lenguajes de programación antes de pasar a las otras formas en que PowerShell las usa.
Una matriz es una estructura de datos que actúa como una colección de varios elementos. Puede iterar por la matriz o acceder a elementos individuales mediante un índice. La matriz se crea como un fragmento secuencial de memoria donde cada valor se almacena justo al lado del otro.
Hablaré sobre cada uno de los detalles a medida que avanzamos.
Uso básico
Dado que las matrices son una característica básica de PowerShell, existe una sintaxis sencilla para trabajar con ellas en PowerShell.
Creación de una matriz
Se puede crear una matriz vacía mediante @()
.
PS> $data = @()
PS> $data.count
0
Podemos crear una matriz e inicializarla con valores, con tan solo colocarlos dentro del paréntesis @()
.
PS> $data = @('Zero','One','Two','Three')
PS> $data.count
4
PS> $data
Zero
One
Two
Three
Esta matriz tiene cuatro elementos. Cuando llamamos a la variable $data
, vemos la lista de nuestros elementos. Si es una matriz de cadenas, obtenemos una línea por cadena.
Se puede declarar una matriz en varias líneas. En este caso, la coma es opcional y, en general, se excluye.
$data = @(
'Zero'
'One'
'Two'
'Three'
)
Prefiero declarar mis matrices en varias líneas de esa forma. No solo es más fácil de leer cuando tiene varios elementos, sino que también facilita la comparación con versiones anteriores cuando se usa el control de código fuente.
Otra sintaxis
Normalmente, se entiende que @()
es la sintaxis para crear una matriz, pero las listas separadas por comas funcionan en la mayoría de las ocasiones.
$data = 'Zero','One','Two','Three'
Write-Output para crear matrices
Un pequeño truco que merece la pena mencionar es que puede usar Write-Output
para crear cadenas en la consola rápidamente.
$data = Write-Output Zero One Two Three
Esto resulta útil porque no es necesario colocar comillas alrededor de las cadenas cuando el parámetro acepta cadenas. Nunca haría esto en un script, pero se puede hacer en la consola.
Acceso a elementos
Ahora que tiene una matriz con elementos, puede acceder a ellos y actualizarlos.
Offset
Para acceder a elementos individuales, usamos los corchetes []
con un valor de desplazamiento que comienza en 0. Así es como obtenemos el primer elemento de la matriz:
PS> $data = 'Zero','One','Two','Three'
PS> $data[0]
Zero
El motivo por el que usamos cero aquí es porque el primer elemento está al principio de la lista, por lo que usamos un desplazamiento de 0 elementos para acceder a él. Para llegar al segundo elemento, es necesario usar un desplazamiento de 1 para omitir el primer elemento.
PS> $data[1]
One
Esto significa que el último elemento está en el desplazamiento 3.
PS> $data[3]
Three
Índice
Ahora puede ver por qué seleccioné esos valores para este ejemplo. He presentado esto como un desplazamiento porque eso es lo que realmente es, pero a este desplazamiento se le conoce de forma más común como un índice. Un índice que comienza en 0
. En el resto de este artículo, utilizaremos el término índice para hacer referencia al desplazamiento.
Trucos especiales sobre índices
En la mayoría de los lenguajes, solo puede especificar un único número como el índice, y se obtendrá un solo elemento. PowerShell es mucho más flexible. Puede usar varios índices a la vez. Al proporcionar una lista de índices, podemos seleccionar varios elementos.
PS> $data[0,2,3]
Zero
Two
Three
Los elementos se devuelven según el orden de los índices proporcionados. Si duplica un índice, obtendrá ese elemento las dos veces.
PS> $data[3,0,3]
Three
Zero
Three
Podemos especificar una secuencia de números con el operador ..
integrado.
PS> $data[1..3]
One
Two
Three
Esto también funciona en orden inverso.
PS> $data[3..1]
Three
Two
One
Puede usar valores de índice negativos para desplazarse desde el final. Por lo tanto, si necesita el último elemento de la lista, puede usar -1
.
PS> $data[-1]
Three
Hay que tener cuidado aquí con el operador ..
. Las secuencias 0..-1
y -1..0
dan como resultado los valores 0,-1
y -1,0
. Es fácil ver $data[0..-1]
y pensar que enumeraría todos los elementos si olvida este detalle. $data[0..-1]
proporciona el mismo valor que $data[0,-1]
al proporcionar el primer y último elemento de la matriz, y ninguno de los demás valores. Este es un ejemplo más grande:
PS> $a = 1,2,3,4,5,6,7,8
PS> $a[2..-1]
3
2
1
8
Esto es igual que:
PS> $a[2,1,0,-1]
3
2
1
8
Fuera de los límites
En la mayoría de los lenguajes, si intenta acceder a un índice de un elemento que va más allá del final de la matriz, obtendría algún tipo de error o una excepción. PowerShell no devuelve nada de forma silenciosa.
PS> $null -eq $data[9000]
True
No se puede indexar en una matriz NULL
Si la variable es $null
e intenta indexarla como una matriz, obtendrá una excepción System.Management.Automation.RuntimeException
con el mensaje Cannot index into a null array
.
PS> $empty = $null
PS> $empty[0]
Error: Cannot index into a null array.
Por lo tanto, asegúrese de que las matrices no son $null
antes de intentar acceder a los elementos que contienen.
Count
Las matrices y otras colecciones tienen una propiedad Count que indica cuántos elementos hay en la matriz.
PS> $data.count
4
PowerShell 3.0 agregó una propiedad Count a la mayoría de los objetos. Puede tener un solo objeto y debe proporcionar un recuento de 1
.
PS> $date = Get-Date
PS> $date.count
1
Incluso $null
tiene una propiedad Count, salvo que devuelve 0
.
PS> $null.count
0
Hay algunas excepciones aquí que revisaré cuando trate la búsqueda de $null
o matrices vacías más adelante en este artículo.
Errores puntuales
Se crea un error de programación común porque las matrices empiezan en el índice 0. Los errores puntuales pueden introducirse de dos maneras.
Lo primero sería pensar que desea el segundo elemento y usa un índice de 2
y obtiene realmente el tercer elemento. O bien, piense que tiene cuatro elementos y desea el último elemento, por lo que usa el recuento para acceder al último elemento.
$data[ $data.count ]
PowerShell puede permitirle hacer eso y proporcionar exactamente el elemento que existe en el índice 4: $null
. Debe usar $data.count - 1
o -1
, dos parámetros sobre los que hemos obtenido información anteriormente.
PS> $data[ $data.count - 1 ]
Three
Aquí es donde puede usar el índice -1
para obtener el último elemento.
PS> $data[ -1 ]
Three
Lee Dailey también me dijo que podemos usar $data.GetUpperBound(0)
para obtener el número de índice máximo.
PS> $data.GetUpperBound(0)
3
PS> $data[ $data.GetUpperBound(0) ]
Three
La segunda forma más común es al iterar la lista y no detenerse en el momento adecuado. Lo revisaré cuando hablemos sobre el uso del bucle for
.
Actualización de elementos
Podemos usar el mismo índice para actualizar los elementos existentes en la matriz. Esto nos proporciona acceso directo para actualizar elementos individuales.
$data[2] = 'dos'
$data[3] = 'tres'
Si se intenta actualizar un elemento que está más allá del último elemento, se obtiene un error Index was outside the bounds of the array.
.
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
Revisaré esto más adelante cuando hable sobre cómo aumentar una matriz.
Iteración
En el algún momento, puede que necesite recorrer la lista completa o iterar por ella para realizar alguna acción en cada elemento de la matriz.
Canalización
Las matrices y la canalización de PowerShell están diseñadas para complementarse. Esta es una de las formas más sencillas de procesar dichos valores. Al pasar una matriz a una canalización, cada elemento contenido en la matriz se procesa individualmente.
PS> $data = 'Zero','One','Two','Three'
PS> $data | ForEach-Object {"Item: [$PSItem]"}
Item: [Zero]
Item: [One]
Item: [Two]
Item: [Three]
Si no ha visto $PSItem
antes, solo tiene que saber que es lo mismo que $_
. Puede usar cualquiera de ellos, ya que ambos representan el objeto actual de la canalización.
Bucle forEach
El bucle ForEach
funciona bien con las colecciones. Uso de la sintaxis: foreach ( <variable> in <collection> )
foreach ( $node in $data )
{
"Item: [$node]"
}
Método forEach
Tiendo a olvidarme de él, pero funciona bien con operaciones sencillas. PowerShell le permite llamar a .ForEach()
en una colección.
PS> $data.foreach({"Item [$PSItem]"})
Item [Zero]
Item [One]
Item [Two]
Item [Three]
.foreach()
adopta un parámetro que es un bloque de script. Puede quitar los paréntesis y simplemente proporcionar el bloque de script.
$data.foreach{"Item [$PSItem]"}
Se trata de una sintaxis menos conocida, pero funciona exactamente igual. Este método foreach
se agregó en PowerShell 4.0.
Bucle For
El bucle for
se usa mucho en muchos de los otros lenguajes, pero no se ve con frecuencia en PowerShell. Cuando lo vea, suele ser en el contexto de recorrer una matriz.
for ( $index = 0; $index -lt $data.count; $index++)
{
"Item: [{0}]" -f $data[$index]
}
Lo primero que hacemos es inicializar $index
en 0
. A continuación, agregamos la condición de que $index
debe ser inferior a $data.count
. Por último, se especifica que cada vez que se cree un bucle, el índice se debe aumentar en 1
. En este caso, $index++
es la forma abreviada de $index = $index + 1
. El operador de formato (-f
) se usa para insertar el valor de $data[$index]
en la cadena de salida.
Siempre que use un bucle for
, preste especial atención a la condición. He usado $index -lt $data.count
aquí. Es fácil obtener una condición algo incorrecta para obtener un error puntual en la lógica. El uso de $index -le $data.count
o $index -lt ($data.count - 1)
siempre suele generar algún error. Esto haría que el resultado procesara demasiados o muy pocos elementos. Este es el típico error puntual.
Bucle switch
Es fácil pasarlo por alto. Si proporciona una matriz a una instrucción switch, esta comprueba cada elemento de la matriz.
$data = 'Zero','One','Two','Three'
switch( $data )
{
'One'
{
'Tock'
}
'Three'
{
'Tock'
}
Default
{
'Tick'
}
}
Tick
Tock
Tick
Tock
Hay muchas cosas interesantes que podemos hacer con la instrucción switch. Tengo otro artículo dedicado a esto.
Actualización de valores
Cuando la matriz es una colección de cadenas o enteros (tipos de valor), puede que a veces desee actualizar los valores de la matriz a medida que se recorren en bucle. La mayoría de los bucles anteriores usan una variable en el bucle que contiene una copia del valor. Si actualiza esa variable, no se actualiza el valor original de la matriz.
La excepción a esa instrucción es el bucle for
. Si desea recorrer una matriz y actualizar los valores que contiene, el bucle for
es lo que busca.
for ( $index = 0; $index -lt $data.count; $index++ )
{
$data[$index] = "Item: [{0}]" -f $data[$index]
}
En este ejemplo, se adopta un valor para el índice, se realizan algunos cambios y, después, se usa ese mismo índice para volver a asignarlo.
Matrices de objetos
Hasta ahora, lo único que hemos colocado en una matriz es un tipo de valor, pero las matrices también pueden contener objetos.
$data = @(
[pscustomobject]@{FirstName='Kevin';LastName='Marquette'}
[pscustomobject]@{FirstName='John'; LastName='Doe'}
)
Muchos cmdlets devuelven colecciones de objetos como matrices cuando se asignan a una variable.
$processList = Get-Process
Todas las características básicas de las que ya se ha hablado también se aplican a las matrices de objetos con algunos detalles que merece la pena destacar.
Acceso a las propiedades
Se puede usar un índice para acceder a un elemento individual de una colección, de la misma forma que con los tipos de valor.
PS> $data[0]
FirstName LastName
----- ----
Kevin Marquette
Se puede acceder a las propiedades y actualizarlas directamente.
PS> $data[0].FirstName
Kevin
PS> $data[0].FirstName = 'Jay'
PS> $data[0]
FirstName LastName
----- ----
Jay Marquette
Propiedades de las matrices
Normalmente, tendría que enumerar la lista completa de la siguiente forma para acceder a todas las propiedades:
PS> $data | ForEach-Object {$_.LastName}
Marquette
Doe
También puede usar el cmdlet Select-Object -ExpandProperty
.
PS> $data | Select-Object -ExpandProperty LastName
Marquette
Doe
Pero PowerShell nos ofrece la posibilidad de solicitar LastName
directamente. PowerShell realiza la enumeración automáticamente y devuelve una lista limpia.
PS> $data.LastName
Marquette
Doe
Aún así, se realiza la enumeración, pero no vemos la complejidad subyacente.
Filtrado con Where-Object
Aquí es donde Where-Object
entra en acción, de tal forma que se permite filtrar y seleccionar lo que se desee fuera de la matriz en función de las propiedades del objeto.
PS> $data | Where-Object {$_.FirstName -eq 'Kevin'}
FirstName LastName
----- ----
Kevin Marquette
Se puede escribir esa misma consulta para obtener el elemento FirstName
que se busca.
$data | Where FirstName -eq Kevin
Where()
Las matrices tienen un método Where()
que permite especificar un elemento scriptblock
para el filtro.
$data.Where({$_.FirstName -eq 'Kevin'})
Esta característica se agregó en PowerShell 4.0.
Actualización de objetos en bucles
Con los tipos de valor, la única manera de actualizar la matriz es usar un bucle for, porque es necesario conocer el índice para reemplazar el valor. Hay más opciones con objetos porque son tipos de referencia. Este es un ejemplo rápido:
foreach($person in $data)
{
$person.FirstName = 'Kevin'
}
Este bucle recorre todos los objetos de la matriz $data
. Dado que los objetos son tipos de referencia, la variable $person
hace referencia al mismo objeto que se encuentra en la matriz. Por tanto, las actualizaciones de sus propiedades actualizan el original.
Todavía no se puede reemplazar todo el objeto de esta manera. Si se intenta asignar un nuevo objeto a la variable $person
, se actualiza la referencia de variable a otro elemento que ya no apunta al objeto original de la matriz. Esto no funciona como cabría esperar:
foreach($person in $data)
{
$person = [pscustomobject]@{
FirstName='Kevin'
LastName='Marquette'
}
}
Operadores
Los operadores de PowerShell también sirven para las matrices. Algunos de ellos funcionan de manera ligeramente diferente.
-join
El operador -join
es el más obvio, por lo que vamos a profundizar en él primero. Me gusta el operador -join
y lo uso con frecuencia. Combina todos los elementos de la matriz con el carácter o la cadena que se especifique.
PS> $data = @(1,2,3,4)
PS> $data -join '-'
1-2-3-4
PS> $data -join ','
1,2,3,4
Una de las características que me gustan del operador -join
es que controla elementos individuales.
PS> 1 -join '-'
1
Lo utilizo dentro de registros y mensajes detallados.
PS> $data = @(1,2,3,4)
PS> "Data is $($data -join ',')."
Data is 1,2,3,4.
-join $array
Este es un truco inteligente que Lee Dailey me indicó. Si alguna vez se desea combinar todo sin un delimitador, en lugar de hacer esto:
PS> $data = @(1,2,3,4)
PS> $data -join $null
1234
Se puede usar -join
con la matriz como parámetro sin prefijo. Eche un vistazo a este ejemplo para saber de qué estoy hablando.
PS> $data = @(1,2,3,4)
PS> -join $data
1234
-replace y -split
Los otros operadores, como -replace
y -split
, se ejecutan en cada elemento de la matriz. No puedo decir que siempre lo he utilizado de esta forma, pero aquí se muestra un ejemplo.
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
-contains
El operador -contains
permite comprobar una matriz de valores para ver si contiene un valor especificado.
PS> $data = @('red','green','blue')
PS> $data -contains 'green'
True
-in
Si tiene un valor único que le gustaría comprobar si coincide con alguno de varios valores, puede usar el operador -in
. El valor se encontraría a la izquierda y la matriz en el lado derecho del operador.
PS> $data = @('red','green','blue')
PS> 'green' -in $data
True
Esto puede resultar complicado si la lista es grande. A menudo, utilizo un patrón regex si voy a comprobar más de unos pocos valores.
PS> $data = @('red','green','blue')
PS> $pattern = "^({0})$" -f ($data -join '|')
PS> $pattern
^(red|green|blue)$
PS> 'green' -match $pattern
True
-eq y -ne
La igualdad con las matrices puede resultar complicada. Cuando la matriz está en el lado izquierdo, se compara cada elemento. En lugar de devolver True
, se devuelve el objeto con el que existe una coincidencia.
PS> $data = @('red','green','blue')
PS> $data -eq 'green'
green
Cuando se usa el operador -ne
, se obtienen todos los valores que no son iguales a nuestro valor.
PS> $data = @('red','green','blue')
PS> $data -ne 'green'
red
blue
Cuando se usa esto en una instrucción if()
, el valor devuelto es True
. Si no se devuelve ningún valor, se trata de un valor False
. En ambos casos, las instrucciones siguientes se evalúan como True
.
$data = @('red','green','blue')
if ( $data -eq 'green' )
{
'Green was found'
}
if ( $data -ne 'green' )
{
'And green was not found'
}
Examinaré esto cuando hablemos de las pruebas de $null
.
-match
El operador -match
intenta coincidir con cada elemento de la colección.
PS> $servers = @(
'LAX-SQL-01'
'LAX-API-01'
'ATX-SQL-01'
'ATX-API-01'
)
PS> $servers -match 'SQL'
LAX-SQL-01
ATX-SQL-01
Cuando se usa -match
con un solo valor, una variable especial $Matches
se rellena con información de coincidencia. Esto no sucede cuando una matriz se procesa de esta manera.
Se puede adoptar el mismo enfoque con Select-String
.
$servers | Select-String SQL
Vamos a profundizar más sobre Select-String
, -match
y la variable $matches
en otra publicación titulada Las distintas formas de usar regex.
$null o valores vacíos
La prueba de $null
o de matrices vacías puede resultar complicada. Estas son las excepciones comunes con las matrices.
A primera vista, parece que esta instrucción debería funcionar.
if ( $array -eq $null)
{
'Array is $null'
}
Sin embargo, acabo de observar cómo -eq
comprueba cada elemento de la matriz. Por tanto, puede haber una matriz de varios elementos con un solo valor $null, que se evaluaría como $true
$array = @('one',$null,'three')
if ( $array -eq $null)
{
'I think Array is $null, but I would be wrong'
}
Esta es la razón por la que se recomienda colocar $null
a la izquierda del operador. Esto hace que este escenario no plantee problemas.
if ( $null -eq $array )
{
'Array actually is $null'
}
Una matriz $null
no es lo mismo que una matriz vacía. Si se sabe que existe una matriz, compruebe el número de objetos que contiene. Si la matriz es $null
, el recuento es 0
.
if ( $array.count -gt 0 )
{
"Array isn't empty"
}
Hay otra excepción que hay que tener en cuenta aquí. Se puede usar count
incluso si tiene un solo objeto, a menos que ese objeto sea PSCustomObject
. Se trata de un error que se corrigió en PowerShell 6.1.
Es algo positivo, pero hay muchas personas que aún usan la versión 5.1 y, por tanto, es necesario tenerlo en cuenta.
PS> $object = [PSCustomObject]@{Name='TestObject'}
PS> $object.count
$null
Si todavía usa PowerShell 5.1, puede encapsular el objeto en una matriz antes de comprobar el recuento para obtener un número preciso.
if ( @($array).count -gt 0 )
{
"Array isn't empty"
}
Para hacerlo con seguridad, compruebe $null
y, después, el recuento.
if ( $null -ne $array -and @($array).count -gt 0 )
{
"Array isn't empty"
}
All -eq
Recientemente observé que alguien preguntó cómo comprobar que todos los valores de una matriz coinciden con un valor determinado. El usuario de Reddit /u/bis tenía esta solución inteligente que comprueba si hay valores incorrectos y, después, cambia el resultado.
$results = Test-Something
if ( -not ( $results -ne 'Passed') )
{
'All results a Passed'
}
Adición a matrices
Llegados a este punto, se empieza a preguntar cómo agregar elementos a una matriz. La respuesta rápida es que no se puede. Una matriz tiene un tamaño de memoria fijo. Si necesita aumentarlo o agregar un solo elemento a ella, se debe crear una matriz y copiar todos los valores de la matriz anterior. Esto suena trabajoso, pero PowerShell elimina la complejidad de crear la matriz. PowerShell implementa el operador de suma (+
) para las matrices.
Nota
PowerShell no implementa una operación de resta. Si quiere una alternativa flexible a una matriz, debe usar un objeto List
genérico.
Adición de matrices
Se puede usar el operador de suma con matrices para crear una matriz. Por lo tanto, dadas estas dos matrices:
$first = @(
'Zero'
'One'
)
$second = @(
'Two'
'Three'
)
Se pueden agregar juntas para obtener una nueva matriz.
PS> $first + $second
Zero
One
Two
Three
Signos más e igual (+=)
Se puede crear una matriz en contexto y agregarle un elemento similar al siguiente:
$data = @(
'Zero'
'One'
'Two'
'Three'
)
$data += 'four'
Recuerde que cada vez que se use +=
, se duplica y crea una matriz. Esto no es un problema para los conjuntos de datos pequeños, pero el escalado es muy deficiente.
Asignación de canalización
Se pueden asignar los resultados de cualquier canalización en una variable. Se trata de una matriz si contiene varios elementos.
$array = 1..5 | ForEach-Object {
"ATX-SQL-$PSItem"
}
Normalmente, al pensar en el uso de la canalización, viene a la mente la típica integración de PowerShell. Se puede utilizar la canalización con instrucciones foreach()
y otros bucles. Por lo tanto, en lugar de agregar elementos a una matriz en un bucle, se pueden colocar elementos en la canalización.
$array = foreach ( $node in (1..5))
{
"ATX-SQL-$node"
}
Tipos de matriz
De forma predeterminada, una matriz de PowerShell se crea como un tipo [PSObject[]]
. Esto permite que contenga cualquier tipo de objeto o valor. Esto funciona porque todo se hereda del tipo PSObject
.
Matrices fuertemente tipadas
Se puede crear una matriz de cualquier tipo con una sintaxis similar. Cuando se crea una matriz fuertemente tipada, solo puede contener valores u objetos del 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
Agregar elementos a una matriz es una de sus mayores limitaciones, pero hay algunas otras colecciones que se pueden usar para solucionar este problema.
ArrayList
suele ser una de las primeras soluciones a las que se recurre cuando se necesita una matriz con la que se pueda trabajar más rápido. Actúa como una matriz de objetos cada vez que se necesita, pero puede agregar los elementos con rapidez.
Aquí se muestra cómo se crea un elemento ArrayList
y cómo se le agregan elementos.
$myarray = [System.Collections.ArrayList]::new()
[void]$myArray.Add('Value')
Se recurre a .NET para obtener este tipo. En este caso, se usa el constructor predeterminado para crearlo. A continuación, se llama al método Add
para agregarle un elemento.
La razón por la que uso [void]
al principio de la línea es para suprimir el código de retorno. Algunas llamadas a .NET permiten hacer esto y pueden crear resultados inesperados.
Si los únicos datos que hay en la matriz son cadenas, eche un vistazo al uso de StringBuilder. Es prácticamente lo mismo, pero tiene algunos métodos que solo se utilizan para tratar cadenas. StringBuilder
está diseñado especialmente para el rendimiento.
Es habitual que las personas pasen a ArrayList
desde las matrices. Pero esto pertenece a una época en la que C# no contaba con compatibilidad genérica. La compatibilidad de ArrayList
con el elemento List[]
genérico ha quedado en desuso.
Lista genérica
Un tipo genérico es un tipo especial de C# que define una clase generalizada, y el usuario especifica los tipos de datos que usa cuando se crea. Por lo tanto, si se desea una lista de números o cadenas, hay que especificar que se desea una lista de tipos int
o string
.
Aquí se muestra cómo crear una lista de cadenas.
$mylist = [System.Collections.Generic.List[string]]::new()
También podría ser una lista de números.
$mylist = [System.Collections.Generic.List[int]]::new()
Se puede convertir una matriz existente en una lista como esta sin crear primero el objeto:
$mylist = [System.Collections.Generic.List[int]]@(1,2,3)
Se puede acortar la sintaxis con la instrucción using namespace
en PowerShell 5 y versiones posteriores. La instrucción using
debe ser la primera línea del script. Al declarar un espacio de nombres, PowerShell permite dejarlo fuera de los tipos de datos cuando se hace referencia a ellos.
using namespace System.Collections.Generic
$myList = [List[int]]@(1,2,3)
Esto hace que List
sea mucho más fácil de usar.
Tiene un método Add
similar a su disposición. A diferencia de ArrayList, no hay ningún valor devuelto en el método Add
, por lo que no tenemos que aplicarle el elemento void
.
$myList.Add(10)
De esta forma, aún se puede acceder a los elementos como otras matrices.
PS> $myList[-1]
10
List[PSObject]
Puede haber una lista de cualquier tipo, pero cuando no se conozca el tipo de objetos, se puede usar [List[PSObject]]
para contenerlos.
$list = [List[PSObject]]::new()
Remove()
ArrayList
y el elemento List[]
genérico admiten la eliminación de elementos de la colección.
using namespace System.Collections.Generic
$myList = [List[string]]@('Zero','One','Two','Three')
[void]$myList.Remove("Two")
Zero
One
Three
Cuando se trabaja con tipos de valor, se quita el primero de la lista. Puede llamarlo una y otra vez para seguir quitando ese valor. Si se tienen tipos de referencia, se debe proporcionar el objeto que se desea quitar.
[list[System.Management.Automation.PSDriveInfo]]$drives = Get-PSDrive
$drives.remove($drives[2])
$delete = $drives[2]
$drives.remove($delete)
El método Remove devuelve true
si pudo encontrar y quitar el elemento de la colección.
Más colecciones
Hay muchas otras colecciones que se pueden usar, pero estas son las sustituciones de matrices genéricas adecuadas. Si le interesa obtener más información sobre estas opciones, eche un vistazo a este gist que Mark Kraus ha organizado.
Otros matices
Ahora que he tratado toda la funcionalidad principal, aquí hay algunas cuestiones más que quería mencionar antes de terminar.
Matrices con un tamaño establecido previamente
He mencionado que no se puede cambiar el tamaño de una matriz una vez creada. Se puede crear una matriz de un tamaño determinado previamente si se le llama con el constructor new($size)
.
$data = [Object[]]::new(4)
$data.count
4
Multiplicación de matrices
Un truquito interesante es que se puede multiplicar una matriz por un entero.
PS> $data = @('red','green','blue')
PS> $data * 3
red
green
blue
red
green
blue
red
green
blue
Inicialización con 0
Un escenario común es la intención de crear una matriz que contenga solo ceros. Si solo va a haber enteros, una matriz fuertemente tipada de enteros, de forma predeterminada, solo contendrá ceros.
PS> [int[]]::new(4)
0
0
0
0
Se puede utilizar el truco de la multiplicación para hacer esto.
PS> $data = @(0) * 4
PS> $data
0
0
0
0
Lo bueno del truco de la multiplicación es que se puede usar cualquier valor. Por lo tanto, si se prefiere tener 255
como valor predeterminado, sería una buena forma de hacerlo.
PS> $data = @(255) * 4
PS> $data
255
255
255
255
Matrices anidadas
Una matriz dentro de una matriz se denomina matriz anidada. No la utilizo mucho en PowerShell, pero sí la he usado más en otros lenguajes. Considere la posibilidad de usar una matriz de matrices cuando los datos se ajusten a un patrón tipo cuadrícula.
A continuación, se muestran dos formas de crear una matriz bidimensional.
$data = @(@(1,2,3),@(4,5,6),@(7,8,9))
$data2 = @(
@(1,2,3),
@(4,5,6),
@(7,8,9)
)
La coma es muy importante en esos ejemplos. Proporcioné un ejemplo anterior de una matriz normal en varias líneas donde la coma era opcional. Esto no sucede con una matriz multidimensional.
La forma en que se usa la notación de índice cambia ligeramente ahora que hay una matriz anidada. Con el elemento $data
anterior, esta es la forma en que se accedería al valor 3.
PS> $outside = 0
PS> $inside = 2
PS> $data[$outside][$inside]
3
Agregue un par de corchetes para cada nivel de anidamiento de matriz. El primer par de corchetes es para la matriz más externa y, después, empiece a trabajar a partir de ahí.
Write-Output -NoEnumerate
En PowerShell, se suelen desajustar o enumerar las matrices. Este es un aspecto fundamental de la forma en que PowerShell usa la canalización, pero hay ocasiones en las que no se desea que esto sea así.
Normalmente, los objetos se canalizan hacia Get-Member
para obtener más información sobre ellos. Al canalizar una matriz hacia ahí, se desajusta, y Get-Member ve los miembros de la matriz y no la matriz real.
PS> $data = @('red','green','blue')
PS> $data | Get-Member
TypeName: System.String
...
Para evitar que se desajuste la matriz, se puede usar Write-Output -NoEnumerate
.
PS> Write-Output -NoEnumerate $data | Get-Member
TypeName: System.Object[]
...
Existe una segunda forma que es más que un truco, y trato de evitar trucos como este. Se puede colocar una coma delante de la matriz antes de canalizarla. Esto encapsula a $data
en otra matriz donde es el único elemento, por lo que después de desencapsular la matriz externa, $data
se vuelve a desencapsular.
PS> ,$data | Get-Member
TypeName: System.Object[]
...
Devolución de una matriz
Este desajuste de matrices también se produce cuando se generan o se devuelven valores a partir de una función. También se puede obtener una matriz si se asigna la salida a una variable, por lo que esto no suele ser un problema.
El problema es que hay una nueva matriz. Si surge algún problema, puede usar Write-Output -NoEnumerate $array
o return ,$array
para solucionarlo.
¿Algo más?
Sé que esto es mucho para asimilar. Espero que aprenda algo de este artículo cada vez que lo lea y que se convierta en una buena referencia a la que recurrir a largo plazo. Si le ha resultado útil, compártalo con otras personas a las que crea que puede servir.
Ahora, recomendaría consultar una publicación similar que escribí sobre las tablas hash.
Comentarios
https://aka.ms/ContentUserFeedback.
Próximamente: A lo largo de 2024 iremos eliminando gradualmente GitHub Issues como mecanismo de comentarios sobre el contenido y lo sustituiremos por un nuevo sistema de comentarios. Para más información, vea:Enviar y ver comentarios de