Обновление значений хеш-таблицы в цикле 'foreach' в PowerShell - PullRequest
31 голосов
/ 04 мая 2011

Я пытаюсь перебрать хэш-таблицу и установить значение каждого ключа равным 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

Что дает и как мне решить эту проблему?

Ответы [ 10 ]

45 голосов
/ 04 мая 2011

Вы не можете изменить Hashtable при перечислении его. Вот что вы можете сделать:

$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
}
12 голосов
/ 15 марта 2012

Существует гораздо более простой способ достижения этого.Вы не можете изменить значение хеш-таблицы при его перечислении из-за того, что это переменная ссылочного типа.Это точно такая же история в .NET.

Используйте следующий синтаксис, чтобы обойти это.Мы преобразуем коллекцию ключей в базовый массив, используя нотацию @().Мы создаем копию коллекции ключей и вместо этого ссылаемся на этот массив, что означает, что теперь мы можем редактировать хеш-таблицу.

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

foreach($key in @($myHash.keys)){
    $myHash[$key] = 5
}
5 голосов
/ 08 июля 2017

Вам не нужно клонировать всю хеш-таблицу для этого примера. Достаточно просто перечислить коллекцию ключей, поместив ее в массив @(...):

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

3 голосов
/ 04 мая 2011

Использование clone:

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

Или в однострочнике:

$myHash = ($myHash.clone()).keys | % {} {$myHash[$_] = 5} {$myHash}
2 голосов
/ 13 ноября 2015

Вы должны проявить творческий подход!

$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
2 голосов
/ 30 апреля 2013

Я новичок в PowerShell, но я большой поклонник использования встроенных функций, потому что считаю его более читабельным. Вот как я бы решил проблему, используя GetEnumerator и Clone. Этот подход также позволяет ссылаться на существующие значения хеша ($ _. Value) для целей модификации.

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

$myHash.Clone().GetEnumerator() | foreach-object {$myHash.Set_Item($_.key, 5)}
0 голосов
/ 14 июня 2019
$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
        }
    }
}

Обновление хеш-значения, если элементы массива совпали с хеш-ключом.

0 голосов
/ 14 июня 2019
$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
0 голосов
/ 12 августа 2016

Как упоминалось в предыдущем ответе, clone - это путь. Мне нужно было заменить любые нулевые значения в хэше на «Неизвестно», и этот однострочный выполняет свою работу.

($record.Clone()).keys | %{if ($record.$_ -eq $null) {$record.$_ = "Unknown"}}
0 голосов
/ 04 мая 2011

Кажется, когда вы обновляете хеш-таблицу внутри цикла foreach, перечислитель делает себя недействительным.Я справился с этим, заполнив новую хэш-таблицу:

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

$newHash = @{}
foreach($key in $myHash.keys){
    $newHash[$key] = 5
}
$myHash = $newHash
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...