J'ai du mal à supprimer la première ligne (ID d'élément) d'un tableau.
$test.GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Object[] System.Array
Pour lister toutes les options que j'ai essayées, ,$test | gm
et qui dit clairement:
Remove Method void IList.Remove(System.Object value)
RemoveAt Method void IList.RemoveAt(int index)
Donc quand j'essaie $test.RemoveAt(0)
j'obtiens l'erreur:
Exception calling "RemoveAt" with "1" argument(s): "Collection was of a fixed size."At line:1 char:1
+ $test.RemoveAt(1)
+ ~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : NotSupportedException
J'ai donc enfin trouvé ici que mon tableau doit être du type System.Object
pour pouvoir utiliser $test.RemoveAt(0)
. Est-il préférable de déclarer tous les tableaux au début du script sous forme de liste? Ou est-il préférable de convertir les tableaux avec $collection = ({$test}.Invoke())
en une liste ultérieurement lorsque cette fonctionnalité est requise?
Quels sont les avantages et les inconvénients des deux types? Merci de votre aide.
Une autre option consiste à utiliser la capacité de Powershell à affecter plusieurs variables (voir Affectation de plusieurs variables sur https://docs.Microsoft.com/en-gb/powershell/module/Microsoft.powershell.core/about/about_assignment_operators?view= powershell-5.1 que j'ai trouvé grâce à cette réponse: https://stackoverflow.com/a/37733801 ).
$arr = 1..5
$first, $rest= $arr
$rest
2
3
4
5
C'est une caractéristique de Powershell depuis plus de dix ans. J'ai trouvé cette fonctionnalité de cet article de blog: https://blogs.msdn.Microsoft.com/powershell/2007/02/05/powershell-tip-how-to-shift-arrays/
Les tableaux ont une taille fixe, comme le dit l'erreur. RemoveAt()
est une méthode héritée qui ne s'applique pas aux tableaux normaux. Pour supprimer la première entrée du tableau, vous pouvez écraser le tableau par une copie comprenant tous les éléments sauf le premier, comme ceci:
$arr = 1..5
$arr
1
2
3
4
5
$arr = $arr[1..($arr.Length-1)]
$arr
2
3
4
5
Si vous devez supprimer des valeurs d'index différents, vous devriez envisager d'utiliser une variable List
. Il prend en charge Add()
, Remove()
et RemoveAt()
:
#If you only have a specific type of objects, like int, string etc. then you should edit `[System.Object] to [System.String], [int] etc.
$list = [System.Collections.Generic.List[System.Object]](1..5)
$list
1
2
3
4
5
$list.RemoveAt(0)
$list
2
3
4
5
Voir mon SO réponse et about_Arrays pour plus de détails sur le fonctionnement des tableaux.
Cela vous permettra de supprimer chaque occurrence d'un élément arbitraire d'un tableau sans recourir à un objet .NET plus sophistiqué.
$x=<array element to remove>
$test = $test | Where-Object { $_ -ne $test[$x] }
Cela fera la même chose, mais n'enlèvera qu'un des éléments. S'il y a des doublons, ils resteront.
$x=<array element to remove>
$skip=$true
$test = $test | ForEach-Object { if (($_ -eq $x) -and $skip) { $skip=$false } else { $_ } }
Vous pouvez utiliser Select-Object -Skip <count>
pour omettre le premier item count:
PS C:\> 1..3 | Select-Object -Skip 1
2
3
PS C:\>
PS C:\> 1 | Select-Object -Skip 1
PS C:\>
Juste pour mettre à jour - il y a un problème avec @Frode F. answer
Si le nombre d'éléments dans le tableau est supérieur à 1
$arr = $arr[1..($arr.Length-1)]
Si le nombre d'éléments est 1, cela ne supprime pas l'élément
if($arr.Length -le 1) {
$arr = @()
}
else {
$arr = $arr[1..($arr.length - 1)]
}
Je pense que cela dépendra des circonstances. Si vous ne devez supprimer que le premier élément une fois, vous pouvez utiliser le découpage en tableau:
$arr = $arr[1..($arr.length-1)]
Si vous envisagez de le faire de manière répétée, vous devriez commencer par un arraylist ou une collection générique. Si c'est un grand tableau, vous pouvez simplement mettre l'expression qui le crée dans un scriptblock et y faire un .invoke () plutôt que de laisser le pipeline créer un tableau puis le convertir en une collection.
Excusez la réponse tardive, mais je me débattais aussi avec cela. Pour ce qui est de mes intentions (écrire dans un fichier texte), je me suis rendu compte que, comme le tableau avait une taille fixe, au lieu de le supprimer, je pouvais simplement définir la valeur sur string.empty.
$results = SQLQuery -connectionString $connectionString -query $query;
$results[0] = '';
foreach ($r in $results) {
Add-Content $skus $r[0];
}
Pour moi, cela s'est débarrassé de l'en-tête que je ne voulais pas dans mon fichier plat. J'espère que cela aide quelqu'un d'autre là-bas.
Si nous avons le cas où un grand tableau (ou ArrayList) doit être exécuté par certaines parties - j'ai utilisé un Lifehack
#$bigArray with thousands of items
while($bigArray.Count -gt 0)
{
if($bigArray.Count -gt 100)
{
$k = 100
}else {$k = $bigArray.Count}
$part = $bigArray | select -First $k
#now we can make some operations with this $part
#in the end of loop we should exclude this part from big array
if($bigArray.Count -gt 100)
{
$bigArray = $bigArray | select -Last ($bigArray.Count - $k)
}else {$bigArray = @()}#in this step we have been handle last part of array and we should null him for stop loop
}
Et maintenant, nous pouvons gérer un grand tableau de plusieurs parties (par 100 éléments)