PowerShell에서 어레이의 모든 개체에서 하나의 속성 값 선택
오브젝트 $objects 배열이 있다고 칩시다.이러한 개체에 "이름" 속성이 있다고 가정합니다.
이것이 내가 하고 싶은 것이다.
$results = @()
$objects | %{ $results += $_.Name }
이것은 효과가 있지만, 더 나은 방법으로 할 수 있을까요?
다음과 같은 작업을 수행할 경우:
$results = objects | select Name
$results
이름 지어주세요.$results name이름 。
더 좋은 방법이 있을까요?
내 생각엔 네가 이 모든 것들을ExpandProperty
「」Select-Object
.
예를 들어 현재 디렉토리의 목록을 가져오고 이름 속성만 표시하려면 다음을 수행합니다.
ls | select -Property Name
아직 디렉토리를 반환하고 있습니다.Info 또는 FileInfo 객체.Get-Member(일명)에 파이프로 연결하여 항상 파이프라인을 통과하는 유형을 검사할 수 있습니다.gm
를 참조해 주세요.
ls | select -Property Name | gm
따라서 개체를 현재 속성 유형으로 확장하려면 다음을 수행합니다.
ls | select -ExpandProperty Name
이 경우 다음 작업을 수행하여 변수를 문자열 배열로 지정할 수 있습니다. 여기서 string은 Name 속성입니다.
$objects = ls | select -ExpandProperty Name
보다 쉬운 솔루션으로서 다음과 같은 것을 사용할 수 있습니다.
$results = $objects.Name
요?$results
Name"에 " 값 $objects
.
기존의 유용한 답변을 보완하기 위해 어떤 접근방식을 사용해야 할지에 대한 지침과 성능 비교를 제공합니다.
파이프라인 [1] 밖에서 다음을 사용합니다(PSv3+ 필요).
$objects.Name # returns .Name property values from all objects in $objects
againandq의 답변에서 알 수 있듯이, 구문적으로 더 간단하고 훨씬 더 빠릅니다.
컬렉션 수준에서 속성에 액세스하여 요소의 값을 배열로 가져오는 것을 멤버 액세스 열거라고 하며 PSv3+ 기능입니다.
또는 PSv2에서는
foreach
출력은 변수에 직접 할당할 수도 있습니다.$140 = foreach ($obj in $140) { $obj.이름 }
(파이프라인) 명령어로부터의 모든 출력을 메모리로 수집할 수 있는 경우 파이프라인을 멤버액세스 열거와 조합할 수도 있습니다.예를 들어 다음과 같습니다.
(Get-ChildItem -File | Where-Object Length -lt 1gb).Name
트레이드오프:
- 입력 수집과 출력 배열은 모두 메모리에 전체적으로 맞아야 합니다.
- 라인를 들어, 「」( 「파이프 라인」)는 다음과 같습니다.
(Get-ChildItem).Name
이 명령어를 실행하여 완료해야 어레이 요소에 액세스할 수 있습니다.
파이프라인에서 결과를 다른 명령어로 전달해야 하는 경우, 특히 원래 입력이 전체적으로 메모리에 맞지 않는 경우 다음을 사용합니다.
$objects | Select-Object - ExpandProperty 이름
- 「 」의
-ExpandProperty
Scott Saad의 답변에 설명되어 있습니다(프로퍼티 값만 얻으려면 필요합니다). - 파이프라인의 스트리밍 동작에 의해 통상적인 파이프라인의 이점을 얻을 수 있습니다.즉, 1개씩의 오브젝트 처리에서는 일반적으로 즉시 출력이 생성되어 메모리 사용량이 일정하게 유지됩니다(최종적으로 결과를 메모리에 수집하지 않는 한).
- 트레이드오프:
- 파이프라인의 사용은 비교적 느리다.
- 「 」의
작은 입력 수집(어레이)의 경우 차이를 알아차리지 못할 수 있으며, 특히 명령줄에서 명령어를 쉽게 입력할 수 있는 것이 더 중요합니다.
여기 입력하기 쉬운 대안이 있습니다. 단, 가장 느린 접근법입니다.ForEach-Object
에일리어스 「」를 통해%
구문을 단순화(다시 말하면 PSv3+): 예를 들어 다음과 같은 PSv3+ 솔루션을 기존 명령어에 쉽게 추가할 수 있습니다.
$objects | % Name # short for: $objects | ForEach-Object -Process { $_.Name }
참고: 이 접근 방식이 느린 주된 이유는 파이프라인 사용이 아닙니다. cmdlet(및 )의 비효율적인 구현이 PowerShell 7.2 이상에 해당하기 때문입니다.이 훌륭한 블로그 투고는 문제를 설명하고 있습니다.기능 요청 GitHub 문제 #10982로 이어졌습니다.다음의 회피책은 동작 속도를 크게 높입니다(이것보다 약간 느립니다).foreach
더 빠르다..ForEach()
# Speed-optimized version of the above.
# (Use `&` instead of `.` to run in a child scope)
$objects | . { process { $_.Name } }
PSv4+ 어레이 방식(이 문서에서 보다 포괄적으로 설명)은 또 하나의 고성능 대안이지만 멤버 액세스 열거와 마찬가지로 먼저 모든 입력을 메모리에 수집해야 합니다.
# By property name (string):
$objects.ForEach('Name')
# By script block (more flexibility; like ForEach-Object)
$objects.ForEach({ $_.Name })
이 접근법은 파이프라인 로직이 적용되지 않는다는 점을 제외하고 동일한 트레이드오프를 갖는 멤버액세스 열거와 비슷합니다.멤버 액세스 열거보다 약간 느리지만 파이프라인보다 현저하게 빠릅니다.
이름(string 인수)으로 단일 속성 값을 추출할 경우 이 솔루션은 member-access enumeration과 동등합니다(단, member-access enumeration은 구문적으로 단순합니다).
스크립트 블록바리안트()
{ ... }
는 임의의 변환을 가능하게 합니다.이는 파이프라인 기반의 cmdlet()%
을 대체하는 고속 올인 메모리입니다.
★★★★★★.ForEach()
array 메서드는 형제(메모리 내 동등한 것)와 마찬가지로 출력 객체가 하나만 생성되는 경우에도 항상 컬렉션(의 인스턴스)을 반환합니다.
은 " " " 입니다.Select-Object
,ForEach-Object
★★★★★★★★★★★★★★★★★」Where-Object
단일 출력 개체를 컬렉션(배열)으로 래핑하지 않고 그대로 반환합니다.
다양한 접근방식의 퍼포먼스 비교
다음은 10회의 실행에서 평균화된 객체 입력 컬렉션을 기반으로 한 다양한 접근 방식의 타이밍 예입니다. 절대 수치는 중요하지 않고 여러 요소에 따라 다르지만 상대적인 성능을 느낄 수 있습니다(이 타이밍은 단일 코어 Windows 10 VM에서 가져옵니다).
중요한
상대적인 퍼포먼스는 입력 객체가 일반 인스턴스인지에 따라 달라집니다.NET 타입(출력 등)
Get-ChildItem
또는 인스턴스(예: 출력)Convert-FromCsv
를 참조해 주세요.
는 ★★★★★★★★★★★★★★★★★★★.[pscustomobject]
속성은 PowerShell에 의해 동적으로 관리되며 (정적으로 정의된) 일반 속성보다 빠르게 액세스할 수 있습니다.NET both both are。두 모두 되어 있습니다.두 시나리오 모두 아래에 설명되어 있습니다.이 테스트에서는 순수 속성 추출 성능에 초점을 맞추기 위해 이미 인 메모리 풀 컬렉션을 입력으로 사용합니다.스트리밍 cmdlet/함수 호출을 입력으로 사용하면 일반적으로 성능 차이는 훨씬 덜합니다. 왜냐하면 해당 호출에 소요되는 시간이 대부분의 시간을 차지하기 때문입니다.
하기 에일리어스 「」를 지정합니다.
%
요.ForEach-Object
sysloglet.
일반적인 결론, 양쪽 모두에 적용됩니다.NET 타입과[pscustomobject]
표시:
멤버 등록()
$collection.Name
및 솔루션은 가장 빠른 파이프라인 기반 솔루션보다 10배 이상 빠릅니다.★★★★★★★★★★★★★★.
% Name
나쁘다% { $_.Name }
- 이 GitHub 문제를 참조하십시오.PowerShell Core는 일관되게 Windows Powershell을 능가합니다.
표준에서의 타이밍NET 유형:
- PowerShell Core v7.0.0-preview.3
Factor Command Secs (10-run avg.)
------ ------- ------------------
1.00 $objects.Name 0.005
1.06 foreach($o in $objects) { $o.Name } 0.005
6.25 $objects.ForEach('Name') 0.028
10.22 $objects.ForEach({ $_.Name }) 0.046
17.52 $objects | % { $_.Name } 0.079
30.97 $objects | Select-Object -ExpandProperty Name 0.140
32.76 $objects | % Name 0.148
- Windows PowerShell v5.1.18362.145
Factor Command Secs (10-run avg.)
------ ------- ------------------
1.00 $objects.Name 0.012
1.32 foreach($o in $objects) { $o.Name } 0.015
9.07 $objects.ForEach({ $_.Name }) 0.105
10.30 $objects.ForEach('Name') 0.119
12.70 $objects | % { $_.Name } 0.147
27.04 $objects | % Name 0.312
29.70 $objects | Select-Object -ExpandProperty Name 0.343
결론:
- PowerShell Core에서는
.ForEach('Name')
능가하다.ForEach({ $_.Name })
Windows PowerShell windows windows windows 。
인스턴스에서의 타이밍:
- PowerShell Core v7.0.0-preview.3
Factor Command Secs (10-run avg.)
------ ------- ------------------
1.00 $objects.Name 0.006
1.11 foreach($o in $objects) { $o.Name } 0.007
1.52 $objects.ForEach('Name') 0.009
6.11 $objects.ForEach({ $_.Name }) 0.038
9.47 $objects | Select-Object -ExpandProperty Name 0.058
10.29 $objects | % { $_.Name } 0.063
29.77 $objects | % Name 0.184
- Windows PowerShell v5.1.18362.145
Factor Command Secs (10-run avg.)
------ ------- ------------------
1.00 $objects.Name 0.008
1.14 foreach($o in $objects) { $o.Name } 0.009
1.76 $objects.ForEach('Name') 0.015
10.36 $objects | Select-Object -ExpandProperty Name 0.085
11.18 $objects.ForEach({ $_.Name }) 0.092
16.79 $objects | % { $_.Name } 0.138
61.14 $objects | % Name 0.503
결론:
를 사용하는 방법에 해 주세요.
[pscustomobject]
★★.ForEach('Name')
스크립트 블록 기반의 변종보다 훨씬 뛰어난 성능을 발휘합니다..ForEach({ $_.Name })
.similarly유 similarly,, similarly 、
[pscustomobject]
에 의해 베이스의 「」가 .Select-Object -ExpandProperty Name
PowerShell과 성능을 합니다..ForEach({ $_.Name })
PowerShell Core의 50%를 사용합니다.요컨대, 다음과 같은 이상한 예외는 제외하고
% Name
, 를 사용하여, 를 참조해 주세요.[pscustomobject]
속성을 참조하는 문자열 기반 메서드는 스크립트 블록 기반 메서드보다 성능이 우수합니다.
테스트 소스 코드:
주의:
기능
Time-Command
이 테스트를 실행할 수 있습니다.링크된 코드가 안전한지 확인했다고 가정하면(개인적으로 확인할 수 있지만 항상 확인해야 합니다), 다음과 같이 직접 설치할 수 있습니다.
irm https://gist.github.com/mklement0/9e1f13978620b09ab2d15da5535d1b27/raw/Time-Command.ps1 | iex
★★
$useCustomObjectInput
로로 합니다.$true
재[pscustomobject]
대신 인스턴스(instance)를 사용합니다.
$count = 1e4 # max. input object count == 10,000
$runs = 10 # number of runs to average
# Note: Using [pscustomobject] instances rather than instances of
# regular .NET types changes the performance characteristics.
# Set this to $true to test with [pscustomobject] instances below.
$useCustomObjectInput = $false
# Create sample input objects.
if ($useCustomObjectInput) {
# Use [pscustomobject] instances.
$objects = 1..$count | % { [pscustomobject] @{ Name = "$foobar_$_"; Other1 = 1; Other2 = 2; Other3 = 3; Other4 = 4 } }
} else {
# Use instances of a regular .NET type.
# Note: The actual count of files and folders in your file-system
# may be less than $count
$objects = Get-ChildItem / -Recurse -ErrorAction Ignore | Select-Object -First $count
}
Write-Host "Comparing property-value extraction methods with $($objects.Count) input objects, averaged over $runs runs..."
# An array of script blocks with the various approaches.
$approaches = { $objects | Select-Object -ExpandProperty Name },
{ $objects | % Name },
{ $objects | % { $_.Name } },
{ $objects.ForEach('Name') },
{ $objects.ForEach({ $_.Name }) },
{ $objects.Name },
{ foreach($o in $objects) { $o.Name } }
# Time the approaches and sort them by execution time (fastest first):
Time-Command $approaches -Count $runs | Select Factor, Command, Secs*
으로는 [1]이 없는 |
파이프라인 운영자는 백그라운드에서 파이프라인을 사용하지만 이 설명의 목적상 파이프라인을 사용하는 것은 다음 명령어를 사용하는 것 뿐입니다.|
파이프라인 연산자, 정의상 여러 명령어가 필요합니다.
주의: 멤버 열거는 컬렉션 자체에 같은 이름의 멤버가 없는 경우에만 작동합니다.따라서 FileInfo 객체의 배열이 있는 경우 파일 길이의 배열은 다음 방법으로 얻을 수 없습니다.
$files.length # evaluates to array length
그리고 "당연히"라고 말하기 전에, 이것을 고려하세요.용량 속성을 가진 개체 배열이 있는 경우
$objarr.capacity
$objarr이 실제로 [Array]가 아닌 [ArrayList]가 아니라면 정상적으로 동작합니다.따라서 멤버 열거를 사용하기 전에 컬렉션이 들어 있는 블랙박스 내부를 확인해야 할 수도 있습니다.
(모델레이터 주의: 이것은 raigandq의 답변에 대한 코멘트가 되어야 하지만, 저는 아직 충분한 평판을 얻지 못했습니다.)
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★!도 그렇게요.★★★★★★★★★★★★★★★★★★★★★★★★★★★★★가 직접 한 예요. '이렇게 하다'$ListOfGGUIDs = $objects.{Object GUID}
먼저 배열로 가 있다는 것을 .$ListOfGGUIDs = @()
언급URL : https://stackoverflow.com/questions/5176815/select-the-values-of-one-property-on-all-objects-of-an-array-in-powershell
'code' 카테고리의 다른 글
SQL Developer에서 SQL Server 스토어드 프로시저를 실행하는 방법 (0) | 2023.04.08 |
---|---|
Array.Add vs += (0) | 2023.04.08 |
Foreach-Object에서 'continue'가 'break'처럼 작동하는 이유는 무엇입니까? (0) | 2023.04.08 |
한 요소가 대기 중일 때 다른 요소에 영향을 미치는 방법 (0) | 2023.04.08 |
"옵션" 매개 변수(각도)UI 라우터를 사용한 JS 상태/뷰 (0) | 2023.04.03 |