【问题标题】:How to add same keys with different values to a hashtable in powershell?如何将具有不同值的相同键添加到powershell中的哈希表?
【发布时间】:2020-10-29 12:29:15
【问题描述】:

这是我使用哈希表数组的代码

$podnumbers = @(1,3,1)

$podInfo = $null
$buffer = 0
$podarray = foreach ($pd in $podnumbers) {
    $podinfo = @()
    for($i=0;$i -lt $pd;$i = $i+1) {
    $pod = Read-Host -Prompt "Assign the pod numbers for",$esxarray[$buffer]
    Write-Output `n
    }
    @{$pd = $pod}
$buffer = $buffer + 1
}

我给 $pod 的输入是 1 = 1 ; 3 = 2,4,6; 1 = 3

我希望我的哈希表数组如下所示,

Key : 1
Value : 1
Name : 1

Key : 3
Value : 2,4,6
Name : 3

Key : 1
Value : 3
Name : 1

但我得到的实际输出是,

Key : 1
Value : 1
Name : 1

Key : 3
Value : 2
Name : 3

Key : 3
Value : 4
Name : 3

Key : 3
Value : 6
Name : 3

Key : 1
Value : 3
Name : 1

【问题讨论】:

  • 你不需要 - 要么添加/修改现有的 key'd 条目,要么找到字典类型以外的东西来保存你的数据:)
  • 既然您似乎配置了 ESX Pod,也许edit 的问题并解释您正在尝试做什么。您可能需要反转键和值。
  • 编辑了我的目标

标签: powershell powershell-5.0 powercli


【解决方案1】:

如果您想为同一个键添加多个值,则需要测试该键是否已经存在并采取相应措施:

$keys = 1,2,3,1
$value = 'a value'
$hashtable = @{}

foreach($key in $keys){
  if(-not $hashtable.ContainsKey($key)){
    # First time we see this key, let's make sure the value is a resizable array
    $hashtable[$key] = @()
  }

  # Now we can safely add values regardless of whether the key already exists
  $hashtable[$key] += $value
}

【讨论】:

  • 根据我的要求,我想为每个 '1' 键添加两次或三次不同值的键 '1'。例如: $hashtable = @{1 = 'host1' ; 2 ='主机2','主机4'; 1 = 'host3'}
  • @DjangoUnchained 是吗?没有什么能阻止你使用上述方法做到这一点
【解决方案2】:

补充@Matthias的答案:
hash table 中不能有重复的键。这是设计使然。哈希表包含基于 binary search algorithm 的唯一键列表,其中每个键都链接到特定对象(值)。

两个解决方法:

1。将一组值添加到特定的哈希表键:

$Keys = 1,2,2,3
$Values = 'a'..'d'
$HashTable = @{}
$i = 0
foreach($key in $Keys){ [array]$HashTable[$Key] += $Values[$i++] }

迭代
缺点是您会丢失项目的顺序(无论您是否使用 ordered 字典,仅仅是因为某些值共享一个键)。

Foreach ($Key in $Hashtable.Keys) {
    Foreach ($Value in @($Hashtable[$Key])) {
        Write-Host $Key '=' $Value
    }
}

3 = d
2 = b
2 = c
1 = a

搜索
优点是项目是二进制索引的,因此可以快速找到。

$SearchKey = 2
Foreach ($Value in @($Hashtable[$SearchKey])) {
    Write-Host $SearchKey '=' $Value
}

2 = b
2 = c

2。或者您可以创建一个哈希表列表(数组) (Key Value Pairs)

$Keys = 1,2,2,3
$Values = 'a'..'d'
$i = 0
$KeyValuePairs = foreach($key in $keys){ @{ $Key = $Values[$i++] } }

迭代
优点是项目将保持有序。
(请注意,您必须调用 GetEnumerator() 方法两次)

$KeyValuePairs.GetEnumerator().GetEnumerator() | Foreach-Object {
    Write-Host $_.Key '=' $_.Value
}

1 = a
2 = b
2 = c
3 = d

搜索
缺点是搜索项目的速度较慢且不太全面。

$SearchKey = 2
$KeyValuePairs.GetEnumerator().GetEnumerator() | 
    Where-Object Key -eq $SearchKey | Foreach-Object {
    Write-Host $_.Key '=' $_.Value
}

2 = b
2 = c

【讨论】:

  • 如果我想给 key(3) 添加 3 个值,应该是这样。例如:对于键 2 = 2 将添加值,对于键 4 = 将添加 4 个值
  • 上面的答案已经显示了。为了更清楚地说明这一点;我用不同的值更新了它(如果你想玩更多的键值,你可以把它改成'a'..'z')。无论如何,如果它仍然不能回答您正在寻找的内容,我建议您使用minimal reproducible example(如上面的示例)和预期的输出(键值对列表)(重新)创建问题,因为我要么我还是不明白你,要么你开始自相矛盾。
【解决方案3】:

我在一个单独的答案中这样做,因为您重新定义的新目标比最初的问题更具体。相反,每个响应都应该分配给相关的 podnumber。

脚本:

$podnumbers = @(1,3,1)
$Inputs = 1,2,4,6,3
$c = 0
$podarray = foreach ($pd in $podnumbers) {
    $podinfo = @{}
    for($i=0; $i -lt $pd; $i = $i+1) {
        # $pod = Read-Host -Prompt "Assign the pod numbers for",$esxarray[$buffer]
        [array]$podinfo[$pd] += $Inputs[$c++]
    }
    $podinfo
}
$podarray

输出:

Name                           Value
----                           -----
1                              {1}
3                              {2, 4, 6}
1                              {3}

【讨论】:

  • 谢谢 iRon,我尝试了上面的脚本,但 $podarray 的写入输出在 cli 中为空
  • 我再次测试过,对我来说,上面的示例适用于 Windows PowerShell 5.1 和 PowerShell Core 7
  • 内部 for 循环外的 $podinfo 即 } $podinfo } 那里需要吗?
  • 只是$podinfoWrite-Output $podinfo 类似,它将数据写入管道,并最终显示。这意味着,您可能会忽略它(如果您不想显示结果)或考虑将其传递给另一个 cmdlet(但这是一个完全不同的问题)。 现在可以了吗?它回答了问题吗?
  • 它既没有抛出错误也没有显示 Write-Output $podarray 的结果
【解决方案4】:

有一种更简单、更快捷的方法:哈希表数组。为此,我将使用“ArrayList”,它是一种非固定大小的数组。

ArrayLists 使 PowerShell 不必在您每次想要添加新项目时重新创建一个数组,这对于 foreach 操作非常有用。

我将继续介绍一个简单的示例,而不是将其集成到您的代码中。考虑到这个问题的年龄,你是否仍然需要它是值得怀疑的,所以这对其他人来说更重要。

示例代码
# Make sure this is initialized outside BEFORE the foreach loop:
$arr = New-Object Collections.ArrayList
#OR
$arr = [Collections.ArrayList]::new()

# Normally the 'Add' method for ArrayList outputs the updated count,
# setting it to the $null variable prevents that.
$null = $arr.Add( @{foo='bar'} )
$null = $arr.Add( @{foo='test'} )

至于迭代结果数组,这里有一些很好的方法:

每项迭代
$arr.ForEach({$_.GetEnumerator()}).ForEach({
  "Key: " + $ht.Key; "Value: " + $ht.Value })

#OR

foreach ($ht in $arr) {
  "Key: " + $ht.Keys; "Value: " + $ht.Values }
输出:
Key: foo
Value: bar
Key: foo
Value: test
每键迭代
foreach ($k in ($arr.Keys | Get-Unique)) {
  "Key: $k"; "Value(s): " + $arr.$k }
输出:
Key: foo
Value(s): bar test

我故意避免在这些示例中使用 ForEach-Object,因为它在每个版本的 PowerShell 中都存在性能问题(7.2.1 是撰写本文时的当前版本)。你可以阅读更多关于here的信息。

【讨论】:

    猜你喜欢
    • 2020-05-31
    • 2011-10-04
    • 1970-01-01
    • 2018-11-13
    • 2020-11-16
    • 1970-01-01
    • 1970-01-01
    • 2018-08-18
    • 2015-12-05
    相关资源
    最近更新 更多