And*_*ehm 20 powershell hashtable
我试图合并两个哈希表,如果第二个中存在相同的键,则覆盖第一个键值对.
为此,我编写了这个函数,如果第二个哈希表中存在相同的键,则首先删除第一个hastable中的所有键值对.
当我逐行输入Powershell时,它可以工作.但是当我运行整个函数时,Powershell要求我提供(它认为)缺少参数到foreach-object.
function mergehashtables($htold, $htnew)
{
$htold.getenumerator() | foreach-object
{
$key = $_.key
if ($htnew.containskey($key))
{
$htold.remove($key)
}
}
$htnew = $htold + $htnew
return $htnew
}
Run Code Online (Sandbox Code Playgroud)
输出:
PS C:\> mergehashtables $ht $ht2
cmdlet ForEach-Object at command pipeline position 1
Supply values for the following parameters:
Process[0]:
Run Code Online (Sandbox Code Playgroud)
$ ht和$ ht2是包含两个键值对的哈希表,其中一个键值对在两个哈希表中都带有键"name".
知道我做错了什么吗?
iRo*_*Ron 24
您可以考虑简单地覆盖它们,而不是删除密钥:
$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
}
Run Code Online (Sandbox Code Playgroud)
对于此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
Run Code Online (Sandbox Code Playgroud)
如果提供的哈希表中存在任何重复键,则会获取最后一个哈希表的值.
(已上传2017-07-09)
一般来说,我更喜欢更多的全局函数,可以使用参数来定制特定需求,如原始问题所示:"如果第二个中存在相同的键,则覆盖第一个中的键值对".为什么让最后一个否决而不是第一个呢?为什么删除任何东西?也许其他人想要合并或加入值或获得最大值或只是平均值...
下面的版本不再支持提供散列表作为参数(您只能将散列表管道传递给函数)但是有一个参数通过操作分配给当前对象($_)中显示的哈希键的值数组,您可以决定如何处理重复条目中的值数组.
功能
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
}
Run Code Online (Sandbox Code Playgroud)
句法
HashTable[] <Hashtables> | Merge-Hashtables [-Operator <ScriptBlock>]
Run Code Online (Sandbox Code Playgroud)
默认默认 情况下,重复哈希表条目中的所有值都将添加到数组中:
PS C:\> $h1, $h2, $h3 | Merge-Hashtables
Name Value
---- -----
e 1
d {4, 2}
b {8, 6}
c {7, 5, 3}
a 9
Run Code Online (Sandbox Code Playgroud)
示例
要获得与版本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
Run Code Online (Sandbox Code Playgroud)
jon*_*n Z 16
我看到两个问题:
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
}
Run Code Online (Sandbox Code Playgroud)
这不是一个新的答案,这在功能上与@ Josh-Petitt的改进相同.
在这个答案中:
Merge-HashTable 如果要将其放入模块中,请使用正确的powershell语法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
Run Code Online (Sandbox Code Playgroud)
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;
}
Run Code Online (Sandbox Code Playgroud)
然后,它可以这样使用:
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
Run Code Online (Sandbox Code Playgroud)
它将产生以下输出:
{
"a": 1,
"d": 42,
"c": {
"val": "value1",
"arr": [
"Foo",
"Bar"
]
},
"b": {
"bb": 33,
"ba": 2,
"bc": "hello"
}
}
Run Code Online (Sandbox Code Playgroud)
小智 5
我只需要这样做并发现它有效:
$HT += $HT2
Run Code Online (Sandbox Code Playgroud)
将的内容$HT2添加到 的内容中$HT。
| 归档时间: |
|
| 查看次数: |
20082 次 |
| 最近记录: |