HOWTO · PowerShell

PowerShell で配列からアイテムを削除する方法

このチュートリアルでは、PowerShell で配列からアイテムを削除する方法を学びます。

このページの内容

PowerShell コレクションから項目を削除するには、まず固定長の配列か ArrayList かを確認します。配列はその場で要素数を減らせません。一方、ArrayList は Remove()、RemoveAt()、または RemoveRange() を使って変更できます。配列から条件に合う項目を残すには、ForEach-Object コマンドレットを使い、その出力を変数に代入します。

以下の例では、値、0 始まりのインデックス、連続する範囲、条件に基づく削除方法を示します。ArrayList のメソッドは既存のコレクションを変更しますが、フィルタリングでは新しい結果が生成されます。

PowerShell の配列と ArrayList のどちらを使うか

$items = @('apple', 'banana', 'cherry') のような PowerShell 配列リテラルは、固定長の配列を作成します。要素の値は置き換えられますが、その場で要素を削除して配列の長さを短くすることはできません。項目を繰り返し追加・削除するコレクションには、System.Collections.ArrayList を使います。その Remove()、RemoveAt()、RemoveRange() メソッドは、同じコレクションを変更します。

主に値の読み取りやフィルタリングを行う場合、または要素数が変わらない場合は配列を使います。コレクションの内容を直接変更する必要がある場合は ArrayList を使います。すでに配列を使っているなら、フィルタリングした結果を代入する方法が、要素数を減らすうえで通常は最もわかりやすい方法です。

値を指定して Remove() で項目を削除する

削除する値を Remove() に渡します。このメソッドは ArrayList から最初に一致した項目を削除し、重複する項目をすべて削除するわけではありません。次の例では、果物のリストから banana を削除します。

次の例を実行します。

このセクションのコードと表示されるラベルや出力は英語のままです。

$items = [System.Collections.ArrayList]::new()
[void]$items.Add('apple')
[void]$items.Add('banana')
[void]$items.Add('cherry')
$items.Remove('banana')
$items

コードと出力ブロック内のラベルや内容は英語のままですが、出力は選択できるテキストです。

apple
cherry

この呼び出しによって $items 自体が変更されます。同じ値が複数回含まれている可能性があり、一致する項目をすべて削除したい場合は、代わりに条件でコレクションをフィルタリングします。

インデックスを指定して RemoveAt() で項目を削除する

位置がわかっている場合は RemoveAt() を使います。ArrayList のインデックスは 0 から始まるため、インデックス 1 は2番目の項目を指します。項目を削除すると、それより後ろの項目が左に詰まり、インデックスも変わります。削除する直前に、現在のコレクションから対象のインデックスを確認してください。

このセクションのコードと表示されるラベルや出力は英語のままです。

$items = [System.Collections.ArrayList]::new()
[void]$items.Add('apple')
[void]$items.Add('banana')
[void]$items.Add('cherry')
$items.RemoveAt(1)
$items

コードと出力ブロック内のラベルや内容は英語のままですが、出力は選択できるテキストです。

apple
cherry

この例では、3項目のリストからインデックス 1 の項目を削除します。メソッドを呼び出す前に、インデックスが 0 から $items.Count - 1 までの範囲内にあることを確認してください。この範囲外のインデックスを指定すると実行時エラーになり、前の項目を削除すると、それ以降の項目のインデックスが変わります。

RemoveRange() で範囲を削除する

RemoveRange(startIndex, count) は、ArrayList から連続する項目を削除します。最初の引数は削除を始める 0 始まりのインデックスで、2番目の引数は削除する項目数です。終了インデックスではありません。たとえば開始インデックスが 1、個数が 2 なら、2番目と3番目の項目が削除されます。

このセクションのコードと表示されるラベルや出力は英語のままです。

$items = [System.Collections.ArrayList]::new()
[void]$items.Add('apple')
[void]$items.Add('banana')
[void]$items.Add('cherry')
[void]$items.Add('date')
[void]$items.Add('elderberry')
$items.RemoveRange(1, 2)
$items

コードと出力ブロック内のラベルや内容は英語のままですが、出力は選択できるテキストです。

apple
date
elderberry

指定する範囲は現在のリスト内に収まっている必要があります。個数が正の場合、開始インデックスは既存の項目を指し、個数によって末尾を超えてはなりません。個数が 0 の場合は何も削除されず、開始インデックスには 0 から現在の Count までを指定できます。Count 自体を指定してもかまいません。ユーザー入力や計算結果を引数に使う場合は、RemoveRange() を呼び出す前に、両方の引数を現在の Count に照らして確認してください。

ForEach-Object で配列をフィルタリングする

ForEach-Object はメソッドではなくコマンドレットです。パイプラインでは、入力された各項目を処理し、条件を満たす項目を出力します。その出力を変数に代入すると、フィルタリングされた配列を作成できます。結果を同じ変数に再代入しない限り、元の配列は変更されません。

このセクションのコードと表示されるラベルや出力は英語のままです。

$items = @('apple', 'banana', 'cherry', 'date', 'elderberry')
$items = $items | ForEach-Object {
    if ($_ -notlike '*a*') {
        $_
    }
}
$items

コードと出力ブロック内のラベルや内容は英語のままですが、出力は選択できるテキストです。

cherry
elderberry

この例の条件は a を含まない文字列を残すため、残る値は cherry と elderberry です。残したい値に合わせて条件を変更してください。既知の値や位置ではなく、プロパティや規則に基づいて項目を削除したい場合に、この方法が役立ちます。

結果を確認し、よくある間違いを避ける

わかっている情報に応じて操作を選びます。ArrayList 内で最初に一致した値を削除するには Remove()、既知の 0 始まりの位置にある1項目を削除するには RemoveAt()、連続する複数の位置から削除するには RemoveRange() を使います。残す項目を条件で決める場合は ForEach-Object を使い、元の配列変数を置き換えるなら、その出力を代入します。

3つの ArrayList メソッドはリストを変更しますが、フィルタリングでは残す項目が出力され、それを代入します。値が出現するたびにすべて削除したい場合は、Remove() を1回呼び出すより、条件によるフィルタリングが適しています。インデックスを使った変更の後は更新後のコレクションで位置を確認し、インデックスと範囲の引数を現在の要素数に照らして検証してください。