PowerShell에서 해시 테이블 병합: 어떻게?
두 개의 해시 테이블을 병합하려고 합니다. 두 번째 해시 테이블에 동일한 키가 있으면 첫 번째 해시 테이블에서 키-값 쌍을 덮어씁니다.
이를 위해 두 번째 해시 테이블에 동일한 키가 존재하는 경우 첫 번째 해시 테이블에서 모든 키-값 쌍을 제거하는 이 함수를 작성했습니다.
PowerShell에 한 줄씩 입력하면 작동합니다.그러나 전체 기능을 실행하면 PowerShell에서 각 개체에 대해 누락된 매개 변수를 제공하도록 요청합니다.
function mergehashtables($htold, $htnew)
{
$htold.getenumerator() | foreach-object
{
$key = $_.key
if ($htnew.containskey($key))
{
$htold.remove($key)
}
}
$htnew = $htold + $htnew
return $htnew
}
출력:
PS C:\> mergehashtables $ht $ht2
cmdlet ForEach-Object at command pipeline position 1
Supply values for the following parameters:
Process[0]:
$ht 및 $ht2는 각각 두 개의 키-값 쌍을 포함하는 해시 테이블이며, 그 중 하나는 두 해시 테이블에 키 "이름"을 포함합니다.
내가 뭘 잘못하고 있는 거지?
병합-해시
키를 제거하는 대신 키를 덮어쓰는 방법을 고려할 수 있습니다.
$h1 = @{a = 9; b = 8; c = 7}
$h2 = @{b = 6; c = 5; d = 4}
$h3 = @{c = 3; d = 2; e = 1}
Function Merge-Hashtables {
$Output = @{}
ForEach ($Hashtable in ($Input + $Args)) {
If ($Hashtable -is [Hashtable]) {
ForEach ($Key in $Hashtable.Keys) {$Output.$Key = $Hashtable.$Key}
}
}
$Output
}
몇 할 수 두 의 입력 되지 않습니다. "cmdlet" " " " " " 있 " " 두 " 블 " 력 " 로 " 이 " 개 " 입 " 의 " 니 " 습 " 의 " 테 " 지 " 되 " 다 " 않 " 한 " 제 " 이 " 경 " 며 " 우 " 으 " 할 " 여 " 러 " 을 " 용 " 수 " 문 " 구 ": 파프라사용:$h1, $h2, $h3 | Merge-Hashtables
사용: 인수 사:Merge-Hashtables $h1 $h2 $h3
또는조합::$h1 | Merge-Hashtables $h2 $h3
위의 모든 예제는 동일한 해시 테이블을 반환합니다.
Name Value
---- -----
e 1
d 2
b 6
c 3
a 9
제공된 해시 테이블에 중복된 키가 있으면 마지막 해시 테이블의 값이 사용됩니다.
(2017-07-09 추가)
병합-해시 테이블 버전 2
일반적으로 "두 번째 키에 동일한 키가 존재하는 경우 첫 번째 키에서 키-값 쌍을 덮어씁니다"라는 원래 질문과 같이 특정 요구에 맞게 매개 변수를 사용자 지정할 수 있는 더 많은 글로벌 기능을 선호합니다.왜 첫 번째 사람이 아니라 마지막 사람이 지배하도록 내버려 두나요?왜 아무것도 제거해야 하나요?다른 사람이 값을 병합하거나 결합하거나 가장 큰 값을 얻거나 평균을 얻으려고 할 수 있습니다.
은 더 하는 것을 수된 값 하여 중복 에서 값 수 매개 를 가지고 .만 함수에 파이프할 수 있음), 현재 개체에 표시된 해시 키에 할당된 값 배열을 작동하여 중복 항목에서 값 배열을 처리하는 방법을 결정할 수 있는 매개 변수를 가지고 있습니다.$_
).
기능.
Function Merge-Hashtables([ScriptBlock]$Operator) {
$Output = @{}
ForEach ($Hashtable in $Input) {
If ($Hashtable -is [Hashtable]) {
ForEach ($Key in $Hashtable.Keys) {$Output.$Key = If ($Output.ContainsKey($Key)) {@($Output.$Key) + $Hashtable.$Key} Else {$Hashtable.$Key}}
}
}
If ($Operator) {ForEach ($Key in @($Output.Keys)) {$_ = @($Output.$Key); $Output.$Key = Invoke-Command $Operator}}
$Output
}
구문
HashTable[] <Hashtables> | Merge-Hashtables [-Operator <ScriptBlock>]
기본값 기본적으로 중복된 해시 테이블 항목의 모든 값이 배열에 추가됩니다.
PS C:\> $h1, $h2, $h3 | Merge-Hashtables
Name Value
---- -----
e 1
d {4, 2}
b {8, 6}
c {7, 5, 3}
a 9
예: 버전 1(마지막 값 사용)과 동일한 결과를 얻으려면 다음 명령을 사용합니다.$h1, $h2, $h3 | Merge-Hashtables {$_[-1]}
첫 번째 값을 대신 사용하려면 다음 명령을 사용합니다.$h1, $h2, $h3 | Merge-Hashtables {$_[0]}
또는 가장 큰 값:$h1, $h2, $h3 | Merge-Hashtables {($_ | Measure-Object -Maximum).Maximum}
.
기타 예:
PS C:\> $h1, $h2, $h3 | Merge-Hashtables {($_ | Measure-Object -Average).Average} # Take the average values"
Name Value
---- -----
e 1
d 3
b 7
c 5
a 9
PS C:\> $h1, $h2, $h3 | Merge-Hashtables {$_ -Join ""} # Join the values together
Name Value
---- -----
e 1
d 42
b 86
c 753
a 9
PS C:\> $h1, $h2, $h3 | Merge-Hashtables {$_ | Sort-Object} # Sort the values list
Name Value
---- -----
e 1
d {2, 4}
b {6, 8}
c {3, 5, 7}
a 9
두 가지 문제가 있습니다.
- 는 개형브스다는같라은있합인니어다야에음과와 같은 줄에 .
Foreach-object
- 컬렉션을 통해 열거하는 동안 컬렉션을 수정하면 안 됩니다.
아래 예제에서는 두 가지 문제를 모두 해결하는 방법을 보여 줍니다.
function mergehashtables($htold, $htnew)
{
$keys = $htold.getenumerator() | foreach-object {$_.key}
$keys | foreach-object {
$key = $_
if ($htnew.containskey($key))
{
$htold.remove($key)
}
}
$htnew = $htold + $htnew
return $htnew
}
새로운 답변이 아닙니다. 이것은 기능적으로 개선된 @Josh-Pett와 동일합니다.
다음 답변:
Merge-HashTable
에서는 이 에 삽입하려면 올바른 합니다.- 실력이 부족하지 않았습니다.해시 테이블 입력의 복제를 추가했습니다. 그렇지 않으면 의도가 아닌 입력이 손상되었습니다.
- 적절한 사용 예를 추가했습니다.
function Merge-HashTable {
param(
[hashtable] $default, # Your original set
[hashtable] $uppend # The set you want to update/append to the original set
)
# Clone for idempotence
$default1 = $default.Clone();
# We need to remove any key-value pairs in $default1 that we will
# be replacing with key-value pairs from $uppend
foreach ($key in $uppend.Keys) {
if ($default1.ContainsKey($key)) {
$default1.Remove($key);
}
}
# Union both sets
return $default1 + $uppend;
}
# Real-life example of dealing with IIS AppPool parameters
$defaults = @{
enable32BitAppOnWin64 = $false;
runtime = "v4.0";
pipeline = 1;
idleTimeout = "1.00:00:00";
} ;
$options1 = @{ pipeline = 0; };
$options2 = @{ enable32BitAppOnWin64 = $true; pipeline = 0; };
$results1 = Merge-HashTable -default $defaults -uppend $options1;
# Name Value
# ---- -----
# enable32BitAppOnWin64 False
# runtime v4.0
# idleTimeout 1.00:00:00
# pipeline 0
$results2 = Merge-HashTable -default $defaults -uppend $options2;
# Name Value
# ---- -----
# idleTimeout 1.00:00:00
# runtime v4.0
# enable32BitAppOnWin64 True
# pipeline 0
전체 해시 테이블 트리를 병합하려는 경우
function Join-HashTableTree {
param (
[Parameter(Mandatory = $true, ValueFromPipeline = $true)]
[hashtable]
$SourceHashtable,
[Parameter(Mandatory = $true, Position = 0)]
[hashtable]
$JoinedHashtable
)
$output = $SourceHashtable.Clone()
foreach ($key in $JoinedHashtable.Keys) {
$oldValue = $output[$key]
$newValue = $JoinedHashtable[$key]
$output[$key] =
if ($oldValue -is [hashtable] -and $newValue -is [hashtable]) { $oldValue | ~+ $newValue }
elseif ($oldValue -is [array] -and $newValue -is [array]) { $oldValue + $newValue }
else { $newValue }
}
$output;
}
그런 다음 다음과 같이 사용할 수 있습니다.
Set-Alias -Name '~+' -Value Join-HashTableTree -Option AllScope
@{
a = 1;
b = @{
ba = 2;
bb = 3
};
c = @{
val = 'value1';
arr = @(
'Foo'
)
}
} |
~+ @{
b = @{
bb = 33;
bc = 'hello'
};
c = @{
arr = @(
'Bar'
)
};
d = @(
42
)
} |
ConvertTo-Json
다음과 같은 출력이 생성됩니다.
{
"a": 1,
"d": 42,
"c": {
"val": "value1",
"arr": [
"Foo",
"Bar"
]
},
"b": {
"bb": 33,
"ba": 2,
"bc": "hello"
}
}
저는 이것이 필요했고 다음과 같은 효과가 있다는 것을 발견했습니다.
$HT += $HT2
『 』의 $HT2
의 됩니다.$HT
.
는 열린브스다같음라은있합니어다야인에과는레와 같은 .ForEach-Object
또는 줄 연속 문자(백티크)를 사용해야 합니다.
{} 내의 코드가 이에 해당하기 때문입니다.정말로 가치가 있습니다.-Process
의 매 변 수 개의 파라미터.ForEach-Object
smdlet.
-Process <ScriptBlock[]>
Specifies the script block that is applied to each incoming object.
이렇게 하면 당면한 문제를 해결할 수 있습니다.
(기존 키를 덮어쓰지 않고) 병합할 수 있는 가장 컴팩트한 코드는 다음과 같습니다.
function Merge-Hashtables($htold, $htnew)
{
$htnew.keys | where {$_ -notin $htold.keys} | foreach {$htold[$_] = $htnew[$_]}
}
PowerShell의 Union and Intersection of Hashtables에서 빌렸습니다.
저는 해시 테이블의 기본 속성이 해시 테이블의 항목에 의해 오버라이드(또는 오버로드)되었을 수 있으므로 일반 함수에서 해시 테이블의 기본 속성을 무차별적으로 참조해서는 안 된다는 점을 지적하고 싶었습니다.
예를 들어 해시 테이블$hash=@{'keys'='lots of them'}
인 기본해테속성갖을됩게니다이블시▁the를 갖게 .Keys
에 keys
래서하것는그▁a것▁and▁thus는▁doing.foreach ($key in $hash.Keys)
항목 대 해 항 된 을 열 합 니거다를 열거합니다.keys
의 값은 속성 Keys
.
"GetEnumerator" 메서드를 사용합니다.keys
의 PSBase
재정의할 수 없는 속성은 기본 속성이 재정의되었는지 여부를 모를 수 있는 함수에서 사용해야 합니다.
테이블에서 키을 '하려면상속')$htOld
hashtables하위테이블시($htNew
테이블에 하지 않고, ), 를 참조하십시오.
function MergeHashtable($htOld, $htNew)
{
$htOld.Keys | %{
if (!$htNew.ContainsKey($_)) {
$htNew[$_] = $htOld[$_];
}
}
return $htNew;
}
이것은 다음을 수정할 것입니다.$htNew
물건.
다음은 파이프라인을 사용하지 않는 함수 버전입니다(파이프라인이 나쁘다는 것이 아니라 다른 방법일 뿐입니다).또한 병합된 해시 테이블을 반환하고 원본을 변경하지 않은 상태로 둡니다.
function MergeHashtable($a, $b)
{
foreach ($k in $b.keys)
{
if ($a.containskey($k))
{
$a.remove($k)
}
}
return $a + $b
}
저는 jon Z의 답변을 확장하거나 단순화하고 싶었습니다.행이 너무 많고 Where-Object를 사용할 수 없는 것 같습니다.단순화된 버전은 다음과 같습니다.
Function merge_hashtables($htold, $htnew) {
$htold.Keys | ? { $htnew.ContainsKey($_) } | % {
$htold.Remove($_)
}
$htold += $htnew
return $htold
}
언급URL : https://stackoverflow.com/questions/8800375/merging-hashtables-in-powershell-how
'programing' 카테고리의 다른 글
PowerShell 버전 정렬 (0) | 2023.09.04 |
---|---|
동일한 디바이저일 때 빠른 AVX512 모듈로 (0) | 2023.09.04 |
판다 데이터 프레임에서 사용하는 메모리를 해제하려면 어떻게 해야 합니까? (0) | 2023.09.04 |
AJAX를 통해 제출하려고 할 때 %5Bobject%20Object%5D(404를 찾을 수 없음) (0) | 2023.09.04 |
.sql 스크립트 내의 MYSQL 클라이언트에서 전달된 -D 매개 변수 값 사용 (0) | 2023.09.04 |