PowerShell 배열, ArrayList 및 컬렉션: 최선의 실천법

PowerShell 스크립트를 작성할 때는 종종 항목 집합을 저장하는 방법이 필요합니다. 이를 위해 배열 또는 특정 유형인 ArrayList를 사용하는 경우가 많습니다. 그렇다면 배열이란 무엇일까요? 배열은 항목 집합을 저장하기 위해 설계된 데이터 구조입니다. 이는 동일한 유형과 다른 유형의 항목을 모두 포함할 수 있습니다.

배열은 여러 프로그래밍 언어에서 사용되며 PowerShell도 예외는 아닙니다. 배열을 생성, 조작 및 최적화하는 다양한 방법이 있습니다. 이 기사에서는 ArrayList, 배열 및 컬렉션에 대해 알아보고 PowerShell과 함께 적용할 때의 몇 가지 모범 사례도 배울 수 있습니다.

사전 요구 사항

PowerShell 언어 자체만 사용하므로 환경적인 사전 요구 사항은 없습니다. Windows PC에 PowerShell이 설치되어 있어야 합니다. 구체적으로 다음이 필요합니다.

  • Windows PowerShell 3 이상
  • .NET Framework 4.5 이상

이와 같은 팁을 더 원하시나요? 제 개인 PowerShell 블로그를 확인해 보세요. 주소는 다음과 같습니다. https://nkasco.com/FriendsOfATA

PowerShell을 사용하여 배열 생성

PowerShell을 사용하여 배열을 생성하는 다양한 방법이 있습니다. 아래에 표시된 것처럼 처리해야 할 이름 목록이 있다고 가정해 봅시다.

John
Susie
Jim
Johnny
Carrie

쉼표로 구분된 요소를 사용하여 배열 생성

가장 기본적인 배열 생성 방법은 아래에 표시된대로 알려진 입력을 변수에 쉼표로 구분하여 할당하는 것입니다.

$BasicArray = "John", "Susie", "Jim", "Johnny", "Carrie"

PowerShell의 모든 개체에 사용 가능한 GetType() 메서드를 실행하면 아래에 표시된 BaseType 속성에 따라 배열이 성공적으로 생성되었음을 확인할 수 있습니다.

PS51> $BasicArray.GetType()

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

서브 표현식 연산자 사용

또한 서브 표현식 연산자를 사용하여 PowerShell에서 배열을 생성할 수도 있습니다. 이 개념은 배열에 추가될 항목 수를 알 수 없을 때 자주 사용됩니다. 생성할 때 결과에는 0개 이상의 항목이 포함될 수 있습니다.

아래에서 $MyArray라는 배열이 내부에 요소가 없이 생성된 것을 알 수 있습니다.

#서브 표현식 연산자를 사용하여 빈 배열 생성
PS51> $MyArray = @()
PS51> $MyArray.count
0

범위 연산자 사용

위에서 보여준 것처럼 배열은 문자열을 저장하는 데만 사용되지 않습니다. 정수와 같은 다른 개체 유형으로도 배열을 생성할 수 있습니다.

순차적인 정수 배열이 필요한 경우, 범위 .. 연산자를 사용하여 단축키를 이용할 수 있습니다. 아래에서는 한 줄의 코드로 정수 2에서 5까지의 배열이 생성된 것을 볼 수 있습니다.

PS51> $NumberedArray = 2..5
PS51> $NumberedArray
2
3
4
5

PowerShell ArrayList 컬렉션 생성

PowerShell ArrayList를 사용하는 것은 PowerShell에서 항목 목록을 저장하는 또 다른 방법입니다. ArrayList 클래스는 .NET의 System.Collections 네임스페이스의 일부입니다. 이 유형의 새 개체를 생성하여 ArrayList 내에 개체를 저장할 수 있습니다.

아래에서는 New-Object cmdlet을 사용하거나 표준 배열을 ArrayList 개체로 캐스트하여 명시적으로 ArrayList 개체를 생성해야 함을 알 수 있습니다.

이 경우에는 BaseType이 객체이고, 위의 예시들은 배열 타입이며 Object 클래스로부터 상속을 받는 것을 보여줍니다. PowerShell은 궁극적으로 .NET 타입 시스템에 대한 액세스를 제공합니다.

PS51> $MyArrayList = New-Object -TypeName "System.Collections.ArrayList"
# 배열을 ArrayList로 캐스팅하는 것도 가능한 옵션입니다
PS51> $MyArrayList = [System.Collections.ArrayList]@()
PS51> $MyArrayList.GetType()

IsPublic IsSerial Name                                     BaseType                                                    
-------- -------- ----                                     --------                                                    
True     True     ArrayList                                System.Object

배열에 아이템 추가하기

배열을 생성할 때, 모든 요소를 생성 시간에 정의하거나 필요할 때 추가할 수 있습니다.

기존 컬렉션에 요소를 추가하기 위해서는 += 연산자나 Add 메서드를 사용할 수 있습니다. 하지만 이들이 작동하는 방식에는 주요한 차이점이 있음을 알아두세요.

@()로 표준 배열을 생성할 때는 += 연산자를 사용하지만, ArrayList에 요소를 추가할 때는 Add 메서드를 사용합니다. 이들 메서드의 차이점은 += 연산자가 실제로 기존 배열을 파괴하고 새 아이템이 있는 새 배열을 생성한다는 것입니다.

아래에서는 배열이나 ArrayList의 IsFixedSize 속성을 참조하여 불변인지 아닌지를 알 수 있습니다.

PS51> $BasicArray.IsFixedSize
True

PS51> $MyArrayList.IsFixedSize
False

기본 배열은 고정 크기의 컬렉션이므로 수정할 수 없습니다.

Add() 메소드를 고정 크기의 배열에 사용하면 고정 크기로 인해 오류가 발생합니다. 아래에서 배열에 항목을 성공적으로 추가할 수 있는 몇 가지 예제를 볼 수 있습니다.

#작동하지 않음
$BasicArray.Add("Nate")

#작동함
$BasicArray += "Nate"
$MyArrayList.Add("Nate")
$MyArrayList += "Nate"

배열에서 항목 제거하기

이제 배열에 항목을 추가하는 방법을 더 잘 이해했으므로 배열에서 항목을 제거하는 몇 가지 방법을 알아보겠습니다.

기본 배열은 고정되어 있으므로 항목을 제거할 수 없습니다. 대신에 완전히 새로운 배열을 생성해야 합니다. 예를 들어, 특정 요소만 포함하려는 조건문을 만들어 배열에서 단일 요소를 제거할 수 있습니다. 아래에 예시가 나와 있습니다.

$NewBasicArray = $BasicArray -ne "Nate"

ArrayList는 고정되어 있지 않으므로 Remove() 메소드를 사용하여 요소를 제거할 수 있습니다. 이는 항목을 자주 추가/제거하려는 경우 ArrayList를 사용하는 경우 중 하나로 도움이 될 수 있습니다.

$MyArrayList.Remove("Nate")

배열 또는 ArrayList에서 특정 항목 검색하기

배열이나 ArrayList에서 특정 항목을 검색하기 위해 여러 가지 다른 메소드를 사용할 수 있습니다. PowerShell의 다른 개체와 마찬가지로 객체를 호출하여 배열의 모든 요소에 액세스할 수 있습니다.

PS51> $BasicArray
John
Susie
Jim
Johnny
Carrie

아마도 첫 번째 요소만 검색해야 하는 경우 배열은 항상 첫 번째 요소를 나타내는 0의 기준을 가지고 있습니다. 배열의 첫 번째 요소를 검색하려면 아래와 같이 대괄호 안에 인덱스 번호를 지정하면 됩니다.

PS51> $BasicArray[0]
John

그 반대로, 배열에서 마지막 X개의 요소를 호출하기 위해 대쉬(음수 표시)를 사용하여 인덱스를 역참조할 수도 있습니다. 배열에서 마지막 요소를 찾는 일반적인 방법은 아래와 같이 -1을 사용하는 것입니다.

PS51> $BasicArray[-1]
Carrie

위에서 배운 범위 연산자는 요소를 호출하는 동일한 방법을 따라 배열의 객체를 검색하는 데에도 사용할 수 있습니다. $BasicArray 배열에서 처음 네 개의 이름을 검색하려고 한다고 가정해 봅시다.

아래에서 볼 수 있듯이, 처음 네 개의 요소를 반환하는 인덱스 범위 0-3을 지정할 수 있습니다.

PS51> $BasicArray[0..3]
John
Susie
Jim
Johnny

PowerShell로 배열 최적화하기

이제 배열을 생성하고 조작하는 방법에 대한 좋은 기초가 있으므로, 어떤 것을 사용해야 할까요? 이에 대답하기 위해 Measure-Command cmdlet을 사용하여 몇 가지 예제를 살펴보겠습니다. Measure-Command cmdlet을 사용하여 명령이 파이프라인을 통해 전달될 때 요소를 처리하는 데 걸리는 시간을 더 잘 이해할 수 있습니다.

일반적으로 작은 개체 컬렉션이 있는 경우 배열을 조작하는 방법에 큰 차이를 느끼지 못할 것입니다. 그러나 큰 개체 컬렉션이 있는 경우 최적의 결과를 얻기 위해 차이점을 이해하는 것이 중요합니다.

이전 섹션에서 +=와 루프와 함께 Add() 메서드 사용 간의 차이점을 배운 내용을 바탕으로 5만 개 항목의 루프를 사용하여 적용해 봅시다.

먼저, 아래와 같이 빈 배열과 빈 ArrayList를 생성하세요.

PS51> $MyArray = @()
PS51> $MyArrayList = [System.Collections.ArrayList]@()

다음, 아래와 같이 범위 연산자와 foreach 루프를 사용하여 각 컬렉션에 50,000개의 요소를 채워 넣으세요.

@(0..50000).foreach({$MyArray += $_})
@(0..50000).foreach({$MyArrayList.Add($_)})

마지막으로, 명령을 표현식으로 래핑하고 그 표현식을 Measure-Command cmdlet에 전달하세요. Measure-Command를 사용하여 표현식을 실행함으로써 각 프로세스가 실제로 실행되는데 걸리는 시간을 확인할 수 있습니다.

기억해야 할 것은, 앞서 배운 것처럼 +=는 실제로 고정된 배열에 추가하지 않고 새로운 배열을 생성한다는 점입니다.

PS51> Measure-Command -Expression {@(0..50000).foreach({$MyArray += $_})}
Days              : 0
Hours             : 0
Minutes           : 0
Seconds           : 59
Milliseconds      : 58
Ticks             : 590585963
TotalDays         : 0.000683548568287037
TotalHours        : 0.0164051656388889
TotalMinutes      : 0.984309938333333
TotalSeconds      : 59.0585963
TotalMilliseconds : 59058.5963

PS51> Measure-Command -Expression {@(0..50000).foreach({$MyArrayList.Add($_)})}
Days              : 0
Hours             : 0
Minutes           : 0
Seconds           : 0
Milliseconds      : 139
Ticks             : 1399989
TotalDays         : 1.62035763888889E-06
TotalHours        : 3.88885833333333E-05
TotalMinutes      : 0.002333315
TotalSeconds      : 0.1399989
TotalMilliseconds : 139.9989

결과는 어떻게 될까요? 거의 60초 대 대신에 139 밀리초 입니다!

보시다시피, 큰 컬렉션에 대해서는 고정 크기 배열 대신 ArrayList를 활용하는 것이 훨씬 빠릅니다.

이 예는 기본적인 예제이지만, 처리 중에 코드가 무엇을 하는지 이해하는 것의 중요성을 강조합니다. 이를 제대로 이해하지 못하면 사용자 경험에 나쁜 영향을 줄 수 있습니다.

ArrayList 대신 배열을 사용하는 것이 유리한 기존 스크립트가 있다면, 이는 하룻밤에 개선할 수 있는 훌륭한 기회가 될 수 있습니다!

추가 자료

이와 같은 팁을 더 원하신다면, 제 개인 PowerShell 블로그를 확인해보세요: https://nkasco.com/FriendsOfATA.

Source:
https://adamtheautomator.com/powershell-array/