更新'中的哈希表值;foreach&x27;PowerShell中的循环

更新'中的哈希表值;foreach&x27;PowerShell中的循环,powershell,Powershell,我试图循环遍历哈希表,并将每个键的值设置为5,PowerShell会给出一个错误: $myHash = @{} $myHash["a"] = 1 $myHash["b"] = 2 $myHash["c"] = 3 foreach($key in $myHash.keys){ $myHash[$key] = 5 } 枚举集合时出错: Collection was modified; enumeration operation may not execute.. At line:1 ch

我试图循环遍历哈希表,并将每个键的值设置为5,PowerShell会给出一个错误:

$myHash = @{}
$myHash["a"] = 1
$myHash["b"] = 2
$myHash["c"] = 3

foreach($key in $myHash.keys){
    $myHash[$key] = 5
}
枚举集合时出错:

Collection was modified; enumeration operation may not execute..
At line:1 char:8
+ foreach <<<< ($key in $myHash.keys){
    + CategoryInfo          : InvalidOperation: (System.Collecti...tableEnumer
   ator:HashtableEnumerator) [], RuntimeException
    + FullyQualifiedErrorId : BadEnumeration
集合被修改;枚举操作可能无法执行。。
第1行字符:8
+foreach枚举时不能修改它。这是您可以做的:

$myHash = @{}
$myHash["a"] = 1
$myHash["b"] = 2
$myHash["c"] = 3

$myHash = $myHash.keys | foreach{$r=@{}}{$r[$_] = 5}{$r}
编辑1

这对您来说更简单吗:

$myHash = @{}
$myHash["a"] = 1
$myHash["b"] = 2
$myHash["c"] = 3

foreach($key in $($myHash.keys)){
    $myHash[$key] = 5
}

似乎当您更新foreach循环内的哈希表时,枚举器本身会失效。我通过填充一个新的哈希表来解决这个问题:

$myHash = @{}
$myHash["a"] = 1
$myHash["b"] = 2
$myHash["c"] = 3

$newHash = @{}
foreach($key in $myHash.keys){
    $newHash[$key] = 5
}
$myHash = $newHash

使用
克隆

foreach($key in ($myHash.clone()).keys){ $myHash[$key] = 5 } foreach($key-in($myHash.clone()).keys){ $myHash[$key]=5 } 或在一行中:

$myHash = ($myHash.clone()).keys | % {} {$myHash[$_] = 5} {$myHash} $myHash=($myHash.clone()).keys |%{}{$myHash[$\]=5}{$myHash}
有一种更简单的方法来实现这一点。无法在枚举哈希表时更改其值,因为它是引用类型变量。这与.NET中的情况完全相同

使用以下语法绕过它。我们正在使用
@()
符号将密钥集合转换为基本数组。我们制作一个keys集合的副本,并引用该数组,这意味着我们现在可以编辑哈希表

$myHash = @{}
$myHash["a"] = 1
$myHash["b"] = 2
$myHash["c"] = 3

foreach($key in @($myHash.keys)){
    $myHash[$key] = 5
}

我是PowerShell新手,但我非常喜欢使用内置函数,因为我发现它更具可读性。这就是我如何使用GetEnumerator和Clone来解决这个问题的方法。这种方法还允许引用现有的散列值($\ 0.value)进行修改

$myHash = @{}
$myHash["a"] = 1 
$myHash["b"] = 2
$myHash["c"] = 3

$myHash.Clone().GetEnumerator() | foreach-object {$myHash.Set_Item($_.key, 5)}

你必须要有创造力

$myHash = @{}
$myHash["a"] = 1
$myHash["b"] = 2
$myHash["c"] = 3

$keys = @()
[array] $keys = $myHash.keys

foreach($key in $keys)
{
    $myHash.Set_Item($key, 5)
}

$myHash

Name                         Value
----                         -----
c                              5
a                              5
b                              5

如前一个回答中所述,
clone
是一条可行之路。我需要用“Unknown”替换散列中的任何空值,这一行程序完成了这项工作

($record.Clone()).keys | %{if ($record.$_ -eq $null) {$record.$_ = "Unknown"}}

对于本例,您不需要克隆整个哈希表。只需通过将密钥集合强制为数组(…)
来枚举它就足够了:

foreach($key in @($myHash.keys)) {...

如果数组元素与哈希键匹配,则更新哈希值。

谢谢zespri----这对于本应是直接操作的操作来说是非常痛苦的……Powershell非常灵活。有很多方法可以完成同样的事情。诚然,学习是需要时间的,但一旦你到了那里,这类东西就变得容易了。我编辑了我的答案,为您提供了一种更直观的方式。这更像是您最初使用的格式。@ted:不客气。如果你满意的话,你可能会接受答案。这是枚举数的本质。如果在枚举时更改集合,则可能会发生不好的情况。就像跳过项目、两次获得相同的项目,或者更糟。@JasonMArcher:现在我同意你的观点,但只是为了论证,你不认为如果你在迭代时在集合中添加/删除项目,你所描述的情况可能会发生吗。从逻辑上讲,将一个值替换为另一个值不应该是一个问题?第二种想法是,对于哈希表,改变值意味着存储的对象可能需要移动到另一个bucket,记住这一点,这种行为是有意义的。相关问题:有人能解释一下我最近得到-2的原因吗?这会有帮助的。这很有效。谢谢您能否解释为什么在修改值之前需要克隆哈希表(Powershell v2不知道是否适用于更高版本)您不能在对哈希表进行枚举时修改哈希表。您可以改进解释OP脚本为何不起作用的答案。Re:`这与.Net中的情况完全相同。`。。。Powershell是.NET。只需说一句。感谢您描述为什么使用@()运算符。它出现在另一个答案中,但他们没有解释发生了什么。
或者我们可以使用foreach($key in@($myHash.keys.clone()){..
当数组和哈希键的值为1时更新哈希值。上面的代码对我来说很好。
$myHash = @{
    Americas = 0;
    Asia = 0;
    Europe = 0;
}

$countries = @("Americas", "Asia", "Europe", "Americas", "Asia")

foreach($key in $($myHash.Keys))
{
    foreach($Country in $countries)
    {
        if($key -eq $Country)
        {
            $myHash[$key] += 1
        }
    }
}

$myHash
$myHash = @{
    Americas = 0;
    Asia = 0;
    Europe = 0;
}

$countries = @("Americas", "Asia", "Europe", "Americas", "Asia")

foreach($key in $($myHash.Keys))
{
    foreach($Country in $countries)
    {
        if($key -eq $Country)
        {
            $myHash[$key] += 1
        }
    }
}