web-dev-qa-db-fra.com

PowerShell Supprimer l'élément [0] d'un tableau

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.

13
DarkLite1

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/

5
Henry Ward

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.

19
Frode F.

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:\>
6
Ron MacNeil

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)]
}
3
Reddy

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.

2
mjolinor

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. 

0
plntxt

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)

0