次の方法で共有


配列について知りたいこと

配列 は、ほとんどのプログラミング言語の基本的な言語機能です。 これらは、避けるのが難しい値またはオブジェクトのコレクションです。 配列と、その提供するすべてのものを詳しく見てみましょう。

この記事の 元のバージョン は、@KevinMarquetteによって書かれたブログに登場しました. PowerShell チームは、このコンテンツを Microsoft と共有してくれた Kevin に感謝します。 PowerShellExplained.comで彼のブログをチェックしてください.

配列とは

まず、配列とは何か、そしてほとんどのプログラミング言語で使用される方法についての基本的な技術的な説明から始めます。その後、PowerShell がそれらを使用する他の方法に移行します。

配列は、複数の項目のコレクションとして機能するデータ構造です。 配列を反復処理したり、インデックスを使用して個々の項目にアクセスしたりできます。 配列は、各値がもう一方の隣に格納されるメモリの順次チャンクとして作成されます。

私たちは行くにつれて、これらの詳細のそれぞれについて触れます。

基本的な使用方法

配列は PowerShell の基本的な機能であるため、PowerShell で操作するための簡単な構文があります。

配列を作成する

空の配列は、次を使用して作成できます。 @()

PS> $data = @()
PS> $data.Count
0

配列を作成し、 @() かっこ内に配置するだけで値をシードできます。

PS> $data = @('Zero','One','Two','Three')
PS> $data.Count
4

PS> $data
Zero
One
Two
Three

この配列には 4 つの項目があります。 $data変数を呼び出すと、項目の一覧が表示されます。 文字列の配列の場合は、文字列ごとに 1 行を取得します。

複数の行で配列を宣言できます。 この場合、コンマは省略可能であり、通常は省略されます。

$data = @(
    'Zero'
    'One'
    'Two'
    'Three'
)

私はそのような複数の行で配列を宣言することを好む。 複数の項目がある場合は読みやすくなりますが、ソース管理を使用する場合は以前のバージョンと比較しやすくなります。

その他の構文

@()は配列を作成するための構文であることが一般的に理解されていますが、コンマ区切りのリストはほとんどの場合機能します。

$data = 'Zero','One','Two','Three'

Write-Output 配列を作成する

言及する価値のあるクールな小さなトリックの1つは、 Write-Output を使用してコンソールで文字列をすばやく作成できることです。

$data = Write-Output Zero One Two Three

パラメーターが文字列を受け入れるときに文字列を引用符で囲む必要がないため、これは便利です。 私はスクリプトでこれを行うことは決してありませんが、コンソールでは公平なゲームです。

アイテムへのアクセス

項目を含む配列が作成されたので、それらの項目にアクセスして更新することができます。

オフセット

個々の項目にアクセスするには、0 から始まるオフセット値で [] 角かっこを使用します。 配列内の最初の項目を取得する方法は次のとおりです。

PS> $data = 'Zero','One','Two','Three'
PS> $data[0]
Zero

ここでゼロを使用する理由は、最初の項目がリストの先頭にあるため、0 個の項目のオフセットを使用して取得するためです。 2 番目の項目に移動するには、オフセット 1 を使用して最初の項目をスキップする必要があります。

PS> $data[1]
One

これは、最後の項目がオフセット 3 であることを意味します。

PS> $data[3]
Three

インデックス

これで、この例で行った値を選んだ理由がわかります。 これが実際のオフセットであるため、これをオフセットとして導入しましたが、このオフセットはより一般的にインデックスと呼ばれます。 0から始まるインデックス。 この記事の残りの部分では、オフセットをインデックスと呼びます。

特殊なインデックスの技法

ほとんどの言語では、インデックスとして 1 つの数値のみを指定でき、1 つの項目が返されます。 PowerShell の方がはるかに柔軟です。 一度に複数のインデックスを使用できます。 インデックスの一覧を指定することで、いくつかの項目を選択できます。

PS> $data[0,2,3]
Zero
Two
Three

項目は、指定されたインデックスの順序に基づいて返されます。 インデックスを複製すると、その項目が 2 回も取得されます。

PS> $data[3,0,3]
Three
Zero
Three

組み込みの .. 演算子を使用して、数値のシーケンスを指定できます。

PS> $data[1..3]
One
Two
Three

これは逆でも動作します。

PS> $data[3..1]
Three
Two
One

負のインデックス値を使用して、末尾からオフセットできます。 そのため、リストの最後の項目が必要な場合は、 -1を使用できます。

PS> $data[-1]
Three

ここでは、 .. 演算子に注意してください。 シーケンスの 0..-1-1..0 は、 0,-1-1,0の値に評価されます。 この詳細を忘れた場合は、 $data[0..-1] を見て、すべての項目を列挙すると考えるのは簡単です。 $data[0..-1] では、配列内の最初と最後の項目 (およびその他の値は指定しません) を指定することで、 $data[0,-1] と同じ値が提供されます。 大きな例を次に示します。

PS> $a = 1,2,3,4,5,6,7,8
PS> $a[2..-1]
3
2
1
8

これは次と同じです。

PS> $a[2,1,0,-1]
3
2
1
8

範囲外

ほとんどの言語では、配列の末尾を超える項目のインデックスにアクセスしようとすると、何らかの種類のエラーまたは例外が発生します。 PowerShell は何も返しません。

PS> $null -eq $data[9000]
True

null 配列にインデックスを作成できません

変数が$nullされていて、配列のようにインデックスを作成しようとすると、メッセージ Cannot index into a null arraySystem.Management.Automation.RuntimeException例外が発生します。

PS> $empty = $null
PS> $empty[0]
Error: Cannot index into a null array.

そのため、配列内の要素にアクセスする前に、配列が $null されていないことを確認してください。

数える

配列やその他のコレクションには、配列内の項目の数を示す Count プロパティがあります。

PS> $data.Count
4

PowerShell 3.0 では、ほとんどのオブジェクトに Count プロパティが追加されました。 1つのオブジェクトを持つことができ、1の数を返すべきです。

PS> $date = Get-Date
PS> $date.Count
1

$nullでも、0を返す以外はCountプロパティがあります。

PS> $null.Count
0

ここでは、この記事の後半で $null または空の配列のチェックについて説明するときに再検討するトラップがいくつかあります。

off-by-one エラー

配列がインデックス 0 から始まるため、一般的なプログラミング エラーが作成されます。 off-by-one エラーが発生する可能性のある状況は 2 つあります。

1 つ目は、2 番目の項目が必要であると精神的に考え、 2 のインデックスを使用して、3 番目の項目を実際に取得する方法です。 または、4 つの項目があり、最後の項目が必要であると考えることで、カウントを使用して最後の項目にアクセスします。

$data[ $data.Count ]

PowerShell では、これを行い、インデックス 4: $nullに存在する項目を正確に指定できます。 上記で学習した $data.Count - 1 または -1 を使用している必要があります。

PS> $data[ $data.Count - 1 ]
Three

ここで、 -1 インデックスを使用して最後の要素を取得できます。

PS> $data[ -1 ]
Three

リー・ダイリーはまた、 $data.GetUpperBound(0) を使用して最大インデックス番号を取得できることを私に指摘しました。

PS> $data.GetUpperBound(0)
3
PS> $data[ $data.GetUpperBound(0) ]
Three

2 番目に一般的な方法は、リストを反復処理するときに、適切なタイミングで停止しない方法です。 forループの使用について話すときは、もう一度説明します。

アイテムの更新

同じインデックスを使用して、配列内の既存の項目を更新できます。 これにより、個々のアイテムを直接更新できます。

$data[2] = 'dos'
$data[3] = 'tres'

最後の要素を超える項目を更新しようとすると、 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

配列を大きくする方法については、後でもう一度説明します。

反復

ある時点で、リスト全体をウォークまたは反復処理し、配列内の各項目に対して何らかのアクションを実行することが必要になる場合があります。

パイプライン

配列と PowerShell パイプラインは相互に使用されます。 これは、これらの値を処理する最も簡単な方法の 1 つです。 配列をパイプラインに渡すと、配列内の各項目が個別に処理されます。

PS> $data = 'Zero','One','Two','Three'
PS> $data | ForEach-Object {"Item: [$PSItem]"}
Item: [Zero]
Item: [One]
Item: [Two]
Item: [Three]

$PSItemを見たことがない場合は、$_と同じであることを知ってください。 どちらもパイプライン内の現在のオブジェクトを表しているため、いずれか 1 つを使用できます。

ForEach ループ

foreach ループはコレクションに対して適切に機能します。 構文の使用: foreach ( <variable> in <collection> )

foreach ( $node in $data )
{
    "Item: [$node]"
}

ForEach メソッド

私はこのことを忘れる傾向がありますが、それは簡単な操作に適しています。 PowerShell を使用すると、コレクションの ForEach() を呼び出すことができます。

PS> $data.ForEach({"Item [$PSItem]"})
Item [Zero]
Item [One]
Item [Two]
Item [Three]

ForEach()は、スクリプト ブロックであるパラメーターを受け取ります。 かっこを削除し、スクリプト ブロックを指定するだけです。

$data.ForEach{"Item [$PSItem]"}

これはあまり知られていない構文ですが、同じように動作します。 この ForEach メソッドは、PowerShell 4.0 で追加されました。

For ループ

for ループは他のほとんどの言語で頻繁に使用されますが、PowerShell ではあまり表示されません。 これを見かけるとしたら、多くの場合、配列を調べるコンテキストにおいてです。

for ( $index = 0; $index -lt $data.Count; $index++)
{
    "Item: [{0}]" -f $data[$index]
}

最初に、$index0に初期化します。 次に、 $index$data.Count未満である必要がある条件を追加します。 最後に、ループするたびに、インデックスを 1増やす必要があることを指定します。 この場合、 $index++$index = $index + 1の略です。 format 演算子 (-f) は、$data[$index]の値を出力文字列に挿入するために使用されます。

for ループを使用するときは常に、条件に特別な注意を払います。 私はここで $index -lt $data.Count 使用しました。 条件を少し取り違えて、ロジック内に off-by-one エラーを発生させるのはたやすいことです。 $index -le $data.Countまたは$index -lt ($data.Count - 1)の使用は、少し間違っています。 これにより、結果が処理される項目が多すぎるか、少なすぎます。 これは、よくある off-by-one エラーです。

switch ループ

これは見落としやすい1つです。 switch ステートメントに配列を指定すると、配列内の各項目がチェックされます。

$data = 'Zero','One','Two','Three'
switch( $data )
{
    'One'
    {
        'Tock'
    }
    'Three'
    {
        'Tock'
    }
    Default
    {
        'Tick'
    }
}
Tick
Tock
Tick
Tock

switch ステートメントを使ってできる素晴らしいことがたくさんあります。 私はこれに専用の別の記事を持っています。

値の更新

配列が文字列または整数 (値型) のコレクションである場合は、配列内の値をループ処理するときに更新することが必要になる場合があります。 上記のループのほとんどは、値のコピーを保持するループ内の変数を使用します。 その変数を更新した場合、配列内の元の値は更新されません。

そのステートメントの例外は、 for ループです。 配列を走査し、その中の値を更新する場合は、for ループが最適な方法です。

for ( $index = 0; $index -lt $data.Count; $index++ )
{
    $data[$index] = "Item: [{0}]" -f $data[$index]
}

この例では、インデックスを使って値を取得し、いくつかの変更を加え、同じインデックスに元に戻します。

オブジェクトの配列

ここまで、配列に配置しているのは値型だけですが、配列にはオブジェクトを含めることもできます。

$data = @(
    [pscustomobject]@{FirstName='Kevin';LastName='Marquette'}
    [pscustomobject]@{FirstName='John'; LastName='Doe'}
)

多くのコマンドレットでは、オブジェクトを変数に割り当てると、オブジェクトのコレクションが配列として返されます。

$processList = Get-Process

既に説明したすべての基本的な機能は、指摘する価値のあるいくつかの詳細を持つオブジェクトの配列に引き続き適用されます。

プロパティへのアクセス

インデックスを使用すると、値型と同様に、コレクション内の個々の項目にアクセスできます。

PS> $data[0]

FirstName LastName
-----     ----
Kevin     Marquette

プロパティに直接アクセスして更新できます。

PS> $data[0].FirstName

Kevin

PS> $data[0].FirstName = 'Jay'
PS> $data[0]

FirstName LastName
-----     ----
Jay       Marquette

配列のプロパティ

通常、すべてのプロパティにアクセスするには、次のようにリスト全体を列挙する必要があります。

PS> $data | ForEach-Object {$_.LastName}

Marquette
Doe

または、 Select-Object -ExpandProperty コマンドレットを使用します。

PS> $data | Select-Object -ExpandProperty LastName

Marquette
Doe

しかし、PowerShell は直接 LastName を要求する機能を提供します。 PowerShell はそれらすべてを列挙し、クリーン なリストを返します。

PS> $data.LastName

Marquette
Doe

列挙は引き続き発生しますが、その背後には複雑さが見られません。

Where-Object のフィルタリング

ここでは、 Where-Object が入ってくるので、オブジェクトのプロパティに基づいて配列から必要なものをフィルター処理して選択できます。

PS> $data | Where-Object {$_.FirstName -eq 'Kevin'}

FirstName LastName
-----     ----
Kevin     Marquette

同じクエリを記述して、探している FirstName を取得できます。

$data | where FirstName -EQ Kevin

どこ()

配列には Where() メソッドがあり、フィルターの scriptblock を指定できます。

$data.Where({$_.FirstName -eq 'Kevin'})

この機能は PowerShell 4.0 で追加されました。

ループ内のオブジェクトの更新

値型の場合、配列を更新する唯一の方法は、値を置き換えるインデックスを知る必要があるため、for ループを使用することです。 オブジェクトは参照型であるため、より多くのオプションがあります。 簡単な例を次に示します。

foreach($person in $data)
{
    $person.FirstName = 'Kevin'
}

このループは、 $data 配列内のすべてのオブジェクトをウォークしています。 オブジェクトは参照型であるため、 $person 変数は配列内にあるのとまったく同じオブジェクトを参照します。 そのため、プロパティを更新すると、元のプロパティが更新されます。

この方法では、オブジェクト全体を置き換えることはできません。 $person変数に新しいオブジェクトを割り当てようとすると、配列内の元のオブジェクトを指さなくなった変数参照を更新します。 これは、次のように機能しません。

foreach($person in $data)
{
    $person = [pscustomobject]@{
        FirstName='Kevin'
        LastName='Marquette'
    }
}

オペレーター

PowerShell の演算子は配列でも機能します。 一部の機能は若干異なります。

-join

-join演算子は最も明白な演算子であるため、最初に見てみましょう。 私は -join 演算子が好きで、頻繁に使用しています。 配列内のすべての要素が、指定した文字または文字列と結合されます。

PS> $data = @(1,2,3,4)
PS> $data -join '-'
1-2-3-4
PS> $data -join ','
1,2,3,4

私が -join 演算子について気に入っている機能の1つは、それが単一の項目を処理することです。

PS> 1 -join '-'
1

私はログと詳細メッセージの中でこれを使用します。

PS> $data = @(1,2,3,4)
PS> "Data is $($data -join ',')."
Data is 1,2,3,4.

-join $array

リー・ダイリーが私に指摘した賢いトリックは次のとおりです。 区切り記号なしですべてを結合する場合は、これを行う代わりに次のようにします。

PS> $data = @(1,2,3,4)
PS> $data -join $null
1234

-joinは、プレフィックスのないパラメーターとして配列と共に使用できます。 この例を見て、私が話していることを確認してください。

PS> $data = @(1,2,3,4)
PS> -join $data
1234

-replace と -split

-replace-splitなどの他の演算子は、配列内の各項目に対して実行されます。 私は今までこのようにそれらを使用したことがあるとは言えませんが、ここに例があります。

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

-contains演算子を使用すると、値の配列を調べて、指定した値が含まれているかどうかを確認できます。

PS> $data = @('red','green','blue')
PS> $data -contains 'green'
True

-in

複数の値のいずれかと一致することを確認する 1 つの値がある場合は、 -in 演算子を使用できます。 値は左側、配列は演算子の右側にあります。

PS> $data = @('red','green','blue')
PS> 'green' -in $data
True

リストが大きい場合、これは高価になる可能性があります。 いくつかの値をチェックしている場合は、正規表現パターンを頻繁に使用します。

PS> $data = @('red','green','blue')
PS> $pattern = "^({0})$" -f ($data -join '|')
PS> $pattern
^(red|green|blue)$

PS> 'green' -match $pattern
True

-eq と -ne

等値と配列は複雑になる可能性があります。 配列が左側にある場合、すべての項目が比較されます。 Trueを返す代わりに、一致するオブジェクトを返します。

PS> $data = @('red','green','blue')
PS> $data -eq 'green'
green

-ne演算子を使用すると、値と等しくないすべての値が取得されます。

PS> $data = @('red','green','blue')
PS> $data -ne 'green'
red
blue

if() ステートメントでこれを使用する場合、返される値はTrue値です。 値が返されない場合は、 False 値です。 次に示す2つのステートメントはどちらもTrueと評価されます。

$data = @('red','green','blue')
if ( $data -eq 'green' )
{
    'Green was found'
}
if ( $data -ne 'green' )
{
    'And green was not found'
}

ここでは、 $nullのテストについて説明するときに、このことを再検討します。

-match

-match演算子は、コレクション内の各項目の照合を試みます。

PS> $servers = @(
    'LAX-SQL-01'
    'LAX-API-01'
    'ATX-SQL-01'
    'ATX-API-01'
)
PS> $servers -match 'SQL'
LAX-SQL-01
ATX-SQL-01

1 つの値で -match を使用すると、特殊な変数 $Matches に一致情報が設定されます。 配列がこのように処理される場合は、これは当たりません。

Select-Stringでも同じアプローチを取ることができます。

$servers | Select-String SQL

私は正規表現を使用する多くの方法と呼ばれる別の投稿でSelect-String-match$Matches変数を詳しく見てみましょう。

$nullまたは空

$nullまたは空の配列のテストは難しい場合があります。 配列の一般的なトラップを次に示します。

一目で、このステートメントは動作するはずです。

if ( $array -eq $null)
{
    'Array is $null'
}

しかし、配列内の各項目 -eq チェックする方法について説明しました。 したがって、単一の$null値を含む複数の項目を持つ配列があり、それを評価すると$trueになります。

$array = @('one',$null,'three')
if ( $array -eq $null)
{
    'I think Array is $null, but I would be wrong'
}

このため、演算子の左側に $null を配置することをお勧めします。 これにより、このシナリオは問題ではありません。

if ( $null -eq $array )
{
    'Array actually is $null'
}

$null配列は、空の配列と同じではありません。 配列があることがわかっている場合は、配列内のオブジェクトの数を確認します。 配列が $null場合、カウントは 0

if ( $array.Count -gt 0 )
{
    "Array isn't empty"
}

ここで注意する必要があるもう 1 つのトラップがあります。 1 つのオブジェクトがある場合でも、そのオブジェクトがPSCustomObjectでない限り、Countを使用できます。 これは、PowerShell 6.1 で修正されたバグです。 それは良いニュースですが、多くの人々はまだ5.1にいるので、それに注意する必要があります。

PS> $object = [pscustomobject]@{Name='TestObject'}
PS> $object.Count
$null

PowerShell 5.1 をまだ使用している場合は、カウントを確認して正確なカウントを取得する前に、オブジェクトを配列でラップできます。

if ( @($array).Count -gt 0 )
{
    "Array isn't empty"
}

安全を確保するために、まず$nullを確認し、その後カウントを確認してください。

if ( $null -ne $array -and @($array).Count -gt 0 )
{
    "Array isn't empty"
}

All -eq

私は最近、Redditの誰かが配列内のすべての値が特定の値と一致することを確認する方法を尋ねるのを見ました。 Reddit ユーザー u/bis 不正な値をチェックし、結果を反転するこの巧妙なソリューションがありました。

$results = Test-Something
if ( -not ( $results -ne 'Passed') )
{
    'All results a Passed'
}

配列への追加

この時点で、配列に項目を追加する方法を疑問に思い始めます。 簡単な答えは、あなたができないということです。 配列はメモリ内の固定サイズです。 拡張する必要がある場合、または 1 つの項目を追加する必要がある場合は、新しい配列を作成し、古い配列からすべての値をコピーする必要があります。 これは多くの作業のように聞こえますが、PowerShell では新しい配列を作成する複雑さが隠されています。 PowerShell は、配列の加算演算子 (+) を実装します。

PowerShell は減算操作を実装しません。 配列に対して柔軟な代替手段が必要な場合は、 ジェネリック List オブジェクトを使用する必要があります。

配列の加算

加算演算子を配列と共に使用して、新しい配列を作成できます。 したがって、次の 2 つの配列が考えられます。

$first = @(
    'Zero'
    'One'
)
$second = @(
    'Two'
    'Three'
)

それらを一緒に追加して新しい配列を取得できます。

PS> $first + $second

Zero
One
Two
Three

Plus は += に等しい

新しい配列を作成し、次のように項目を追加できます。

$data = @(
    'Zero'
    'One'
    'Two'
    'Three'
)
$data += 'four'

+=を使用するたびに、新しい配列を複製して作成することに注意してください。 これは小さなデータセットには問題ありませんが、規模が大きくなると非常に効率が悪くなります。

パイプラインの割り当て

任意のパイプラインの結果を変数に割り当てることができます。 複数の項目が含まれている場合は配列です。

$array = 1..5 | ForEach-Object {
    "ATX-SQL-$PSItem"
}

通常、パイプラインを使用する場合は、一般的な PowerShell ワンライナーについて考えてみます。 foreach()ステートメントやその他のループを使用してパイプラインを活用できます。 そのため、ループ内の配列に項目を追加する代わりに、項目をパイプラインにドロップできます。

$array = foreach ( $node in (1..5))
{
    "ATX-SQL-$node"
}

配列の型

既定では、PowerShell の配列は [psobject[]] 型として作成されます。 これにより、任意の種類のオブジェクトまたは値を格納できます。 これは、すべてが PSObject 型から継承されるために機能します。

厳密に型指定された配列

同様の構文を使用して、任意の型の配列を作成できます。 厳密に型指定された配列を作成する場合は、指定した型の値またはオブジェクトのみを含めることができます。

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

配列への項目の追加は最大の制限事項の 1 つですが、この問題を解決するために他にもいくつかのコレクションがあります。

ArrayListは、一般的に、処理が速い配列が必要な場合に最初に考える事項の 1 つです。 これは、必要な場所ごとにオブジェクト配列のように機能しますが、項目の追加は迅速に処理されます。

ここでは、 ArrayList を作成し、それに項目を追加する方法を示します。

$myarray = [System.Collections.ArrayList]::new()
[void]$myArray.Add('Value')

この型を取得するために .NET を呼び出しています。 この場合、既定のコンストラクターを使用して作成します。 次に、 Add メソッドを呼び出して項目を追加します。

私が行の先頭で [void] を使用している理由は、リターンコードを抑制するためです。 一部の .NET 呼び出しではこれを行い、予期しない出力が発生する可能性があります。

配列に含まれるデータが文字列のみである場合は、 StringBuilder の使用も参照してください。 これはほとんど同じですが、文字列を処理するためのメソッドがいくつかあります。 StringBuilderはパフォーマンスのために特別に設計されています。

配列から ArrayList に移動するユーザーを見るのは一般的です。 しかし、C# が一般的なサポートを受けていなかった時代から来ています。 ArrayListは、ジェネリックのサポートでは非推奨ですList[]

汎用リスト

ジェネリック型は、一般化されたクラスを定義する C# の特殊な型であり、ユーザーは作成時に使用するデータ型を指定します。 したがって、数値または文字列のリストが必要な場合は、 int または string 型のリストを定義します。

文字列のリストを作成する方法を次に示します。

$mylist = [System.Collections.Generic.List[string]]::new()

または、数値のリスト。

$mylist = [System.Collections.Generic.List[int]]::new()

最初にオブジェクトを作成せずに、既存の配列を次のようなリストにキャストできます。

$mylist = [System.Collections.Generic.List[int]]@(1,2,3)

PowerShell 5 以降の using namespace ステートメントで構文を短縮できます。 usingステートメントは、スクリプトの最初の行である必要があります。 PowerShell では、名前空間を宣言することで、参照時にデータ型から離すことができます。

using namespace System.Collections.Generic
$myList = [List[int]]@(1,2,3)

これにより、 List がはるかに使用可能になります。

同様の Add メソッドを使用できます。 ArrayList とは異なり、 Add メソッドには戻り値がないため、 void する必要はありません。

$myList.Add(10)

また、他の配列のような要素にアクセスすることもできます。

PS> $myList[-1]
10

List[psobject]

任意の型のリストを作成できますが、オブジェクトの種類がわからない場合は、 [List[psobject]] を使用してオブジェクトを格納できます。

$list = [List[psobject]]::new()

削除()

ArrayListとジェネリック List[]は、どちらもコレクションからの項目の削除をサポートします。

using namespace System.Collections.Generic
$myList = [List[string]]@('Zero','One','Two','Three')
[void]$myList.Remove("Two")
Zero
One
Three

値型を操作すると、最初の型がリストから削除されます。 繰り返し呼び出して、その値を削除し続けることができます。 参照型がある場合は、削除するオブジェクトを指定する必要があります。

[List[System.Management.Automation.PSDriveInfo]]$drives = Get-PSDrive
$drives.Remove($drives[2])
$delete = $drives[2]
$drives.Remove($delete)

remove メソッドは、コレクションから項目を検索および削除できた場合に true を返します。

その他のコレクション

他にも多くのコレクションを使用できますが、これらは一般的な配列の置換として適しています。 これらのオプションの詳細について学習することに興味がある場合は、マーク・クラウスがまとめたこのギストを見てみましょう。

その他の微妙な違い

すべての主要な機能について説明したので、これをまとめる前にもう少し触れたいことがいくつかあります。

事前にサイズ定義された配列

私は、配列が作成された後に配列のサイズを変更することはできませんと述べました。 new($size) コンストラクターを使用して呼び出すことで、事前に決定されたサイズの配列を作成できます。

$data = [Object[]]::new(4)
$data.Count
4

配列の乗算

興味深い小さなトリックは、配列に整数を乗算できることです。

PS> $data = @('red','green','blue')
PS> $data * 3
red
green
blue
red
green
blue
red
green
blue

0 で初期化する

一般的なシナリオは、ゼロをすべて含む配列を作成することです。 整数のみを使用する場合、整数の厳密に型指定された配列は既定ですべてのゼロに設定されます。

PS> [int[]]::new(4)
0
0
0
0

乗算トリックを使用してこれを行うことができます。

PS> $data = @(0) * 4
PS> $data
0
0
0
0

乗算トリックの素晴らしい点は、任意の値を使用できることです。 したがって、既定値として 255 したい場合は、これを行うのに適した方法です。

PS> $data = @(255) * 4
PS> $data
255
255
255
255

入れ子になった配列

配列内の配列は、入れ子になった配列と呼ばれます。 PowerShell ではこれらをあまり使用しませんが、他の言語でより多く使用しています。 データがグリッド状に整理できる場合は、二次元配列を使用することを検討してください。

2 次元配列を作成する 2 つの方法を次に示します。

$data = @(@(1,2,3),@(4,5,6),@(7,8,9))

$data2 = @(
    @(1,2,3),
    @(4,5,6),
    @(7,8,9)
)

これらの例では、コンマが非常に重要です。 コンマが省略可能な複数行の通常の配列の前の例を示しました。 これは多次元配列の場合ではありません。

インデックス表記の使用方法は、入れ子になった配列が作成されたので少し変わります。 上記の $data を使用して、値 3 にアクセスする方法を次に示します。

PS> $outside = 0
PS> $inside = 2
PS> $data[$outside][$inside]
3

配列の入れ子のレベルごとに括弧のセットを追加します。 最初の 1 組の角かっこは、一番外側の配列を対象とし、そこから順番に内側に入っていきます。

Write-Output -NoEnumerate

PowerShell では、配列のラップを解除または列挙するのが好きです。 これは、PowerShell がパイプラインを使用する方法の中核的な側面ですが、これを行いたくない場合があります。

普段、オブジェクトの詳細を知るためにオブジェクトをGet-Memberにパイプします。 パイプを使用して配列をそれに渡すと、ラップが解除され、Get-Member は実際の配列ではなく配列のメンバーを認識します。

PS> $data = @('red','green','blue')
PS> $data | Get-Member
TypeName: System.String
...

配列のラップ解除を防ぐには、 Write-Output -NoEnumerateを使用できます。

PS> Write-Output -NoEnumerate $data | Get-Member
TypeName: System.Object[]
...

私は、もう1つの方法があって、それはどちらかというとハック的です(そして、私はこのようなハックを避けるようにしています)。 パイプを使用する前に、配列の前にコンマを配置できます。 これにより、$data は、それが唯一の要素である別の配列にラップされます。そのため、外側の配列のラップを解除すると、$data がラップされずに戻ります。

PS> ,$data | Get-Member
TypeName: System.Object[]
...

配列を返す

この配列のラップ解除は、関数から値を出力または返すときにも発生します。 出力を変数に割り当てた場合でも配列を取得できるため、これは一般的に問題になりません。

ただし、新しい配列があります。 問題が発生した場合は、 Write-Output -NoEnumerate $array または return ,$array を使用して回避できます。

ほかに何か。

これは全て理解するのが大変だと分かっています。 私の願いは、あなたがそれを読むたびにこの記事から何かを学び、それが長い間あなたに良い参考になるということです。 これが役に立つことがわかった場合は、価値があると思われる他のユーザーと共有してください。

ここから、 ハッシュテーブルについて書いたのと同じような投稿をチェックすることをお勧めします。