Program Club

PowerShell 배열 초기화

proclub 2020. 10. 30. 21:17
반응형

PowerShell 배열 초기화


PowerShell에서 배열을 초기화하는 가장 좋은 방법은 무엇입니까?

예를 들어, 코드

$array = @()
for($i=0; $i -lt 5;$i++)
{
    $array[$i] = $FALSE
}

오류를 생성

Array assignment failed because index '0' was out of range.
At H:\Software\PowerShell\TestArray.ps1:4 char:10
+         $array[$ <<<< i] = $FALSE

또 다른 대안 :

for ($i = 0; $i -lt 5; $i++) 
{ 
  $arr += @($false) 
}

$ arr가 아직 정의되지 않은 경우 작동합니다.

참고 -이 작업을 수행하는 더 나은 (그리고 더 많은 성능) 방법이 있습니다 ... 아래의 https://stackoverflow.com/a/234060/4570을 예로 참조 하십시오 .


매우 간결한 두 가지 방법이 더 있습니다.

$arr1 = @(0) * 20
$arr2 = ,0 * 20

형식화 된 배열을 만들려면 생성자기본값을 사용할 수도 있습니다 .

> $a = new-object bool[] 5
> $a
False
False
False
False
False

bool 의 기본값 은 분명히 false 이므로 귀하의 경우에 작동합니다. 마찬가지로 형식화 된 int [] 배열 을 생성 하면 기본값 인 0을 얻게됩니다.

배열을 초기화하는 데 사용하는 또 다른 멋진 방법은 다음과 같은 속기입니다.

> $a = ($false, $false, $false, $false, $false)
> $a
False
False
False
False
False

또는 범위를 초기화하고 싶을 때 유용하다고 생각되는 경우가 있습니다.

> $ a = (1..5)   
> $ a
1
2
4
5

이것이 다소 도움이 되었기를 바랍니다!


원래 예제에서는 배열이 비어 있기 때문에 오류를 반환 한 다음 n 번째 요소에 액세스하여 값을 할당하려고합니다.

여기에 창의적인 답변이 많이 있으며,이 게시물을 읽기 전에는 몰랐던 많은 답변이 있습니다. 작은 어레이에는 모두 괜찮지 만 n0rd가 지적했듯이 성능에는 상당한 차이가 있습니다.

여기서는 Measure-Command를 사용하여 각 초기화에 걸리는 시간을 확인합니다. 짐작할 수 있듯이 명시 적 PowerShell 루프를 사용하는 모든 접근 방식은 .Net 생성자 또는 PowerShell 연산자 (IL 또는 네이티브 코드로 컴파일 됨)를 사용하는 접근 방식보다 느립니다.

요약

  • New-Object@(somevalue)*n(100,000 요소에 대한 주위 20K 진드기가) 빠르다.
  • 범위 연산자를 사용하여 배열을 만드는 n..m것은 10 배 더 느립니다 (200k 틱).
  • 또는 (일명 , )를 Add()사용하여 이미 크기가 조정 된 배열을 반복하는 것처럼 메서드 와 함께 ArrayList를 사용하면 기준선 (2 천만 틱)보다 1000 배 느립니다 .for()ForEach-Objectforeach%
  • 추가하는 +=것은 최악입니다 (단지 1000 개 요소에 대해 2M 틱).

전반적으로 다음과 같은 이유로 array * n 이 "최고" 라고 말하고 싶습니다 .

  • 빠르다.
  • 유형의 기본값뿐만 아니라 모든 값을 사용할 수 있습니다.
  • 반복되는 값을 만들 수 있습니다 (설명을 위해 powershell 프롬프트에 다음을 입력하십시오. (1..10)*10 -join " "또는 ('one',2,3)*3).
  • 간결한 구문.

유일한 단점 :

  • 분명하지 않습니다. 이전에이 구조를 본 적이 없다면 어떤 역할을하는지 분명하지 않습니다.

그러나 배열 요소를 어떤 값으로 초기화하려는 많은 경우에는 강력한 형식의 배열이 정확히 필요한 것입니다. 모든 것을으로 초기화하는 경우 $false배열은 $false또는 이외의 다른 항목을 보유 $true합니까? 그렇지 않은 경우 New-Object type[] n"최상의"접근 방식입니다.

테스팅

기본 배열을 만들고 크기를 지정한 다음 값을 할당합니다.

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

Boolean 배열을 만드는 것은 Object 배열보다 약간 느립니다.

PS> Measure-Command -Expression {$a = New-Object bool[] 100000} | Format-List -Property "Ticks"
Ticks : 130968

이것이 무엇을하는지 명확하지 않습니다. New-Object에 대한 문서에서는 두 번째 매개 변수가 .Net 개체 생성자에 전달되는 인수 목록이라고 말합니다. 배열의 경우 매개 변수는 분명히 원하는 크기입니다.

+ =로 추가

PS> $a=@()
PS> Measure-Command -Expression { for ($i=0; $i -lt 100000; $i++) {$a+=$false} } | Format-List -Property "Ticks"

완료되기를 기다리는 데 지쳤으므로 ctrl + c 다음 :

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

(6 * 3)이 (6 + 6 + 6)과 개념적으로 유사 하듯이 ($ somearray * 3)은 ($ somearray + $ somearray + $ somearray)와 동일한 결과를 제공해야합니다. 그러나 배열에서 +는 덧셈이 아니라 연결입니다.

$ array + = $ element가 느린 경우 $ array * $ n도 느릴 것으로 예상 할 수 있지만 그렇지 않습니다.

PS> Measure-Command -Expression { $a = @($false) * 100000 } | Format-List -Property "Ticks"
Ticks : 20131

Java에 추가 할 때 여러 개체를 만들지 않도록 StringBuilder 클래스가있는 것처럼 PowerShell에는 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

범위 연산자 및 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

메모:

  • 각 실행 ( $a=$null) 사이의 변수를 무효화했습니다 .
  • 테스트는 Atom 프로세서가있는 태블릿에서 이루어졌습니다. 다른 컴퓨터에서 더 빠른 속도를 볼 수 있습니다. [편집 : 데스크톱 컴퓨터에서 약 2 배 빠릅니다.]
  • 여러 번 시도했을 때 약간의 변화가있었습니다. 정확한 숫자보다는 자릿수를 찾으십시오.
  • Testing was with PowerShell 3.0 in Windows 8.

Acknowledgements

Thanks to @halr9000 for array*n, @Scott Saad and Lee Desmond for New-Object, and @EBGreen for ArrayList.

Thanks to @n0rd for getting me to think about performance.


$array = 1..5 | foreach { $false }

$array = @()
for($i=0; $i -lt 5; $i++)
{
    $array += $i
}

Here's another idea. You have to remember, that it's .NET underneath:

$arr = [System.Array]::CreateInstance([System.Object], 5)
$arr.GetType()
$arr.Length

$arr = [Object[]]::new(5)
$arr.GetType()
$arr.Length

Result:

IsPublic IsSerial Name                                     BaseType                                                                                               
-------- -------- ----                                     --------                                                                                               
True     True     Object[]                                 System.Array                                                                                           
5
True     True     Object[]                                 System.Array                                                                                           
5

Using new() has one distinct advantage: when you're programming in ISE and want to create an object, ISE will give you hint with all paramer combinations and their types. You don't have that with New-Object, where you have to remember the types and order of arguments.

ISE IntelliSense for new object


The solution I found was to use the New-Object cmdlet to initialize an array of the proper size.

$array = new-object object[] 5 
for($i=0; $i -lt $array.Length;$i++)
{
    $array[$i] = $FALSE
}

If I don't know the size up front, I use an arraylist instead of an array.

$al = New-Object System.Collections.ArrayList
for($i=0; $i -lt 5; $i++)
{
    $al.Add($i)
}

Or try this an idea. Works with powershell 5.0+.

[bool[]]$tf=((,$False)*5)

참고URL : https://stackoverflow.com/questions/226596/powershell-array-initialization

반응형