Quel est le meilleur moyen d'initialiser un tableau dans PowerShell?
Par exemple, le code
$array = @()
for($i=0; $i -lt 5;$i++)
{
$array[$i] = $FALSE
}
génère l'erreur
Array assignment failed because index '0' was out of range.
At H:\Software\PowerShell\TestArray.ps1:4 char:10
+ $array[$ <<<< i] = $FALSE
Encore une autre alternative:
for ($i = 0; $i -lt 5; $i++)
{
$arr += @($false)
}
Celui-ci fonctionne si $ arr n'est pas encore défini.
NOTE - il existe des méthodes plus performantes (et plus performantes) ... voir https://stackoverflow.com/a/234060/4570 ci-dessous.
Voici deux autres moyens très concis.
$arr1 = @(0) * 20
$arr2 = ,0 * 20
Vous pouvez également vous fier à la valeur default du constructeur si vous souhaitez créer un tableau typé:
> $a = new-object bool[] 5
> $a
False
False
False
False
False
La valeur par défaut de bool est apparemment false donc cela fonctionne dans votre cas. De même, si vous créez un tableau int [] typé, vous obtiendrez la valeur par défaut 0.
Une autre façon intéressante d’initialiser des tableaux consiste à utiliser le raccourci suivant:
> $a = ($false, $false, $false, $false, $false)
> $a
False
False
False
False
False
Ou, si vous le souhaitez, vous souhaitez initialiser une plage, j'ai parfois trouvé cela utile:
> $ a = (1..5) > $ a 1 2
J'espère que c'était un peu utile!
L'exemple d'origine renvoie une erreur car le tableau est créé vide, puis vous essayez d'accéder au nième élément pour lui attribuer une valeur.
Il y a un certain nombre de réponses créatives ici, beaucoup que je ne connaissais pas avant de lire ce post. Tout va bien pour un petit tableau, mais comme le souligne n0rd, il existe des différences de performances significatives.
Ici, j'utilise Measure-Command pour savoir combien de temps prend chaque initialisation. Comme vous pouvez le deviner, toute approche utilisant une boucle PowerShell explicite est plus lente que celles qui utilisent des constructeurs .Net ou des opérateurs PowerShell (qui seraient compilés en langage IL ou en code natif).
New-Object
et @(somevalue)*n
sont rapides (environ 20 000 ticks pour 100 000 éléments). n..m
est 10 fois plus lente (200 000 ticks). Add()
est 1000 fois plus lente que la ligne de base (20 millions de ticks), tout comme une boucle dans un tableau déjà dimensionné utilisant for()
ou ForEach-Object
(a.k.a. foreach
, %
). +=
est le pire (2 millions de ticks pour seulement 1000 éléments). Globalement, je dirais quearray * nest "meilleur" parce que:
(1..10)*10 -join " "
ou ('one',2,3)*3
)Le seul inconvénient:
Mais gardez à l'esprit que dans de nombreux cas où vous souhaitez initialiser les éléments du tableau à une valeur quelconque, un tableau fortement typé correspond exactement à ce dont vous avez besoin. Si vous initialisez tout à $false
, le tableau contiendra-t-il autre chose que $false
ou $true
? Si ce n'est pas le cas, New-Object type[] n
est la "meilleure" approche.
Créez et redimensionnez un tableau par défaut, puis affectez des valeurs:
PS> Measure-Command -Expression {$a = new-object object[] 100000} | Format-List -Property "Ticks"
Ticks : 20039
PS> Measure-Command -Expression {for($i=0; $i -lt $a.Length;$i++) {$a[$i] = $false}} | Format-List -Property "Ticks"
Ticks : 28866028
Créer un tableau de Boolean est un peu plus lent qu'un tableau d'Object:
PS> Measure-Command -Expression {$a = New-Object bool[] 100000} | Format-List -Property "Ticks"
Ticks : 130968
Ce n'est pas évident, la documentation de New-Object indique simplement que le second paramètre est une liste d'arguments transmise au constructeur d'objet .Net. Dans le cas des tableaux, le paramètre est évidemment la taille souhaitée.
Ajout avec + =
PS> $a=@()
PS> Measure-Command -Expression { for ($i=0; $i -lt 100000; $i++) {$a+=$false} } | Format-List -Property "Ticks"
J'en avais marre d'attendre que ça se termine, alors ctrl + c alors:
PS> $a=@()
PS> Measure-Command -Expression { for ($i=0; $i -lt 100; $i++) {$a+=$false} } | Format-List -Property "Ticks"
Ticks : 147663
PS> $a=@()
PS> Measure-Command -Expression { for ($i=0; $i -lt 1000; $i++) {$a+=$false} } | Format-List -Property "Ticks"
Ticks : 2194398
Tout comme (6 * 3) est conceptuellement similaire à (6 + 6 + 6), donc ($ somearray * 3) doit donner le même résultat que ($ somearray + $ somearray + $ somearray). Mais avec les tableaux, + est la concaténation plutôt que l'addition.
Si $ array + = $ element est lent, vous pouvez vous attendre à ce que $ array * $ n soit également lent, mais ce n'est pas:
PS> Measure-Command -Expression { $a = @($false) * 100000 } | Format-List -Property "Ticks"
Ticks : 20131
Tout comme Java a une classe StringBuilder pour éviter de créer plusieurs objets lors de l'ajout, il semble donc que PowerShell possède une ArrayList.
PS> $al = New-Object System.Collections.ArrayList
PS> Measure-Command -Expression { for($i=0; $i -lt 1000; $i++) {$al.Add($false)} } | Format-List -Property "Ticks"
Ticks : 447133
PS> $al = New-Object System.Collections.ArrayList
PS> Measure-Command -Expression { for($i=0; $i -lt 10000; $i++) {$al.Add($false)} } | Format-List -Property "Ticks"
Ticks : 2097498
PS> $al = New-Object System.Collections.ArrayList
PS> Measure-Command -Expression { for($i=0; $i -lt 100000; $i++) {$al.Add($false)} } | Format-List -Property "Ticks"
Ticks : 19866894
Opérateur de plage et boucle Where-Object
:
PS> Measure-Command -Expression { $a = 1..100000 } | Format-List -Property "Ticks"
Ticks : 239863
Measure-Command -Expression { $a | % {$false} } | Format-List -Property "Ticks"
Ticks : 102298091
Remarques:
$a=$null
).Merci à @ halr9000 pour le tableau * n, @Scott Saad et Lee Desmond pour New-Object et @EBGreen pour ArrayList.
Merci à @ n0rd de m'avoir fait penser à la performance.
$array = 1..5 | foreach { $false }
$array = @()
for($i=0; $i -lt 5; $i++)
{
$array += $i
}
Voici une autre idée. Vous devez vous rappeler que c'est .NET en dessous:
$arr = [System.Array]::CreateInstance([System.Object], 5)
$arr.GetType()
$arr.Length
$arr = [Object[]]::new(5)
$arr.GetType()
$arr.Length
Résultat:
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Object[] System.Array
5
True True Object[] System.Array
5
Utiliser new()
présente un avantage distinct: lorsque vous programmez dans ISE et que vous voulez créer un objet, ISE vous indiquera toutes les combinaisons de paramètres et leurs types. Vous n'avez pas cela avec New-Object
, où vous devez vous rappeler les types et l'ordre des arguments.
La solution que j'ai trouvée consistait à utiliser l'applet de commande New-Object pour initialiser un tableau de la taille appropriée.
$array = new-object object[] 5
for($i=0; $i -lt $array.Length;$i++)
{
$array[$i] = $FALSE
}
Si je ne connais pas la taille à l'avance, j'utilise un aryliste au lieu d'un tableau.
$al = New-Object System.Collections.ArrayList
for($i=0; $i -lt 5; $i++)
{
$al.Add($i)
}
Ou essayez ceci une idée. Fonctionne avec Powershell 5.0+.
[bool[]]$tf=((,$False)*5)