我正在尝试将数组转变为键值对作为哈希表,此过程似乎创建了一个哈希表列表,但它们的行为几乎按预期进行。我怎样才能按照预期创建一个哈希表?来自Python,我期待类似字典理解的东西..
PS > ('1','2','3') | foreach {@{($_+'A') = $_}}
Name Value
---- -----
1A 1
2A 2
3A 3
PS > (('1','2','3') | foreach {@{($_+'A') = $_}}).'1A'
1
PS > (('1','2','3') | foreach {@{($_+'A') = $_}})['1A']
您的管道发出[1]
[hashtable]
实例数组,在每次迭代中构造一个哈希表文字。
成员访问枚举 - 即能够访问 collection 级别的属性并返回 elements' 属性值 - 仅适用于
.
(成员访问运算符) ,不适用于 [...]
,索引运算符
请参阅 GitHub 问题 #17514,了解有关这种不对称性的讨论,该不对称性被声明为 设计所致。
[2]
# Works, but only due to use of . rather than []
@(
@{ '1A' = 1 }
@{ '2A' = 2 }
@{ '3A' = 3 }
).'1A' # -> 1
发出一个单个哈希表实例,请使用以下内容,这样您就可以互换使用点和索引表示法:
(
('1','2','3') |
foreach { $ht = @{} } { $ht[$_+'A'] = $_ } { $ht }
)['1A'] # -> 1
请注意使用带有 foreach
(
ForEach-Object
) 的 Three脚本块,它们分别绑定到
-Begin
、
-Process
和
-End
参数。
-Begin
块初始化哈希表,
-Process
块向其中添加条目,
-End
块发出现已填充的哈希表。请注意,
$ht
变量将保留在调用者的作用域中,这可能是这里所需要的;但是,您可以使用
{ $ht; Remove-Variable ht }
作为
-End
块来防止这种情况。
[1] 严格来说,它streams多个实例是成功的输出流,当通过(...)
捕获时,它变成一个
[object[]]
数组。
[2] 在成员访问枚举期间,不具有所请求属性的元素将被简单地跳过,但有一个例外
bug:[pscustomobject]
实例意外地向输出贡献了
$null
值 - 请参阅GitHub问题#13752。
https://gist.github.com/YoraiLevi/292bb8d0e2ce0f87d37e5d5d735fff16
function ConvertTo-Hashtable {
<#
.LINK
https://gist.github.com/YoraiLevi/292bb8d0e2ce0f87d37e5d5d735fff16
.LINK
https://stackoverflow.com/questions/77265408/powershell-array-to-hashtable-cannot-get-keys-value-with-bracket-notation-but-d
.LINK
https://peps.python.org/pep-0274/
.SYNOPSIS
Converts input objects into a hashtable.
.DESCRIPTION
The ConvertTo-Hashtable function converts input objects into a hashtable. It can be used to create a hashtable from an array of values or from pipeline input. The function takes a scriptblock that is used to generate the hashtable values. The scriptblock is executed for each input object and must output a single hashtable. The function can handle duplicate keys in the input objects and provides options for how to handle them.
.PARAMETER ScriptBlock
The scriptblock that is used to generate the hashtable values. The scriptblock is executed for each input object and must output a single hashtable.
.PARAMETER InputArray
An array of input objects to convert to a hashtable.
.PARAMETER InputObject
An input object to convert to a hashtable.
.PARAMETER DuplicateKeyAction
Specifies how to handle duplicate keys in the input objects. Valid values are 'Stop', 'Ignore', 'Overwrite', 'Append', and 'Prepend'. The default value is 'Stop'.
.EXAMPLE
ConvertTo-Hashtable 1, 2, 3
Name Value
---- -----
3 3
2 2
1 1
.EXAMPLE
1, 2, 3 | ConvertTo-Hashtable
Name Value
---- -----
3 3
2 2
1 1
.EXAMPLE
1, 2, 3 | ConvertTo-Hashtable { @{($_ + 1) = $_ } }
Name Value
---- -----
4 3
3 2
2 1
.EXAMPLE
1, 2, 3 | ConvertTo-Hashtable { @{($PSItem + 1) = $PSItem } }
Name Value
---- -----
4 3
3 2
2 1
.EXAMPLE
1, 2, 3 | ConvertTo-Hashtable { @{($args[0] + 1) = $args[0] } }
Name Value
---- -----
4 3
3 2
2 1
.EXAMPLE
1, 2, 3 | ConvertTo-Hashtable { @{($input[0] + 1) = $input[0] } }
Name Value
---- -----
4 3
3 2
2 1
.EXAMPLE
1, '2', 3 | ConvertTo-Hashtable { if ($_ -is [int]) { @{$_ = $_ } } else { [pscustomobject]@{} } }
Scriptblock execution resulted in an error/exception: 'Provided scriptblock must only output a single hashtable, but output type was System.Management.Automation.PSCustomObject'
.EXAMPLE
1, '2', 3 | ConvertTo-Hashtable { if ($_ -is [int]) { @{$_ = $_ } } else { Write-Error 'Write-Error example' } }
Scriptblock execution resulted in an error/exception: 'Write-Error example'
.EXAMPLE
1, '2', '3' | ConvertTo-Hashtable { if ($_ -is [int]) { @{$_ = $_ } }else { throw 'throw example' } }
Scriptblock execution resulted in an error/exception: 'throw example'
.EXAMPLE
1, $null, 3 | ConvertTo-Hashtable { @{$_ = $_ } }
Scriptblock execution resulted in an error/exception: 'A null key is not allowed in a hash literal.'
.EXAMPLE
$i = 0
ConvertTo-Hashtable 1, 1, 1, 2 { @{$_ = ($_ + $i) } ; $i++; }
Scriptblock execution resulted in an error/exception: Key '1' was found multiple times
.EXAMPLE
$i = 0
ConvertTo-Hashtable 1, 1, 1, 2 { @{$_ = $_ + $i } ; $i++; } -DuplicateKeyAction Stop
Scriptblock execution resulted in an error/exception: Key '1' was found multiple times
.EXAMPLE
$i = 0
ConvertTo-Hashtable 1, 1, 1, 2 { @{$_ = $_ + $i } ; $i++; } -DuplicateKeyAction Ignore
Name Value
---- -----
2 5
1 1
.EXAMPLE
$i = 0
ConvertTo-Hashtable 1, 1, 1, 2 { @{$_ = $_ + $i } ; $i++; } -DuplicateKeyAction Overwrite
Name Value
---- -----
2 5
1 3
.EXAMPLE
$i = 0
ConvertTo-Hashtable 1, 1, 1, 2 { @{$_ = $_ + $i } ; $i++; } -DuplicateKeyAction Append
Name Value
---- -----
2 {5}
1 {1, 2, 3}
.EXAMPLE
$i = 0
ConvertTo-Hashtable 1, 1, 1, 2 { @{$_ = $_ + $i } ; $i++; } -DuplicateKeyAction Prepend
Name Value
---- -----
2 {5}
1 {3, 2, 1}
#>
[CmdletBinding( DefaultParameterSetName = 'Pipeline')]
param(
[ValidateNotNull()]
[Parameter(ParameterSetName = 'Call', Position = 1)]
[Parameter(ParameterSetName = 'Pipeline', Position = 0)]
[scriptblock]$ScriptBlock = { @{$_ = $_ } },
[Parameter(Mandatory = $true, Position = 0, ParameterSetName = 'Call')]
[array]$InputArray,
[Parameter(ValueFromPipeline = $true, ParameterSetName = 'Pipeline')]
[psobject]$InputObject,
[ValidateSet('Stop', 'Ignore', 'Overwrite', 'Append', 'Prepend')]
[string]$DuplicateKeyAction = 'Stop'
)
begin {
$ht = @{}
}
process {
try {
$InputObject = switch ($PsCmdlet.ParameterSetName) {
'Call' {
$InputArray
}
'Pipeline' {
@($InputObject)
}
}
$tables = $InputObject | ForEach-Object {
try {
$PreviousErrorActionPreference = $ErrorActionPreference
$ErrorActionPreference = 'Stop'
$table = Invoke-Command -NoNewScope -ScriptBlock $ScriptBlock -InputObject $_ -ArgumentList $_
$ErrorActionPreference = $PreviousErrorActionPreference
}
catch {
$PSCmdlet.ThrowTerminatingError(
[System.Management.Automation.ErrorRecord]::new(
([System.ArgumentException]::New("Scriptblock execution resulted in an error/exception: '$($PSItem.Exception.Message)'", $_)),
'ScriptBlockException',
[System.Management.Automation.ErrorCategory]::InvalidResult,
$ScriptBlock
)
)
}
if ($table -isnot [hashtable]) {
$PSCmdlet.ThrowTerminatingError(
[System.Management.Automation.ErrorRecord]::new(
([System.ArgumentException]::New("Provided scriptblock must only output a single hashtable, but output type was $($table.GetType())")),
'ArgumentException',
[System.Management.Automation.ErrorCategory]::InvalidResult,
$ScriptBlock
)
)
}
$table
}
$tables | ForEach-Object {
$table = $_
$table.GetEnumerator() | ForEach-Object {
$Key = $_.Key
$Value = switch ($DuplicateKeyAction) {
'Stop' {
if (!$ht.ContainsKey($Key)) {
Write-Output -NoEnumerate $table.$key
}
else {
$PSCmdlet.ThrowTerminatingError(
[System.Management.Automation.ErrorRecord]::new(
([System.ArgumentException]::New("Key '$($Key)' was found multiple times")),
'ArgumentException',
[System.Management.Automation.ErrorCategory]::InvalidData,
$Key
)
)
}
}
'Ignore' {
if (!$ht.ContainsKey($Key)) {
Write-Output -NoEnumerate $table.$key
}
else {
Write-Output -NoEnumerate $ht.$key
}
}
'Overwrite' { Write-Output -NoEnumerate $table.$key }
'Append' {
if (!$ht.ContainsKey($Key)) {
Write-Output -NoEnumerate @($table.$key)
}
else {
Write-Output -NoEnumerate ($ht.$key + @($table.$key))
}
}
'Prepend' {
if (!$ht.ContainsKey($Key)) {
Write-Output -NoEnumerate @(, $table.$key)
}
else {
Write-Output -NoEnumerate (@(, $table.$key) + $ht.$key)
}
}
}
$ht.$Key = $Value
}
}
}
catch {
$PSCmdlet.ThrowTerminatingError($PSItem)
}
}
end {
return $ht
}
}