Обновление значений хеш-таблицы в цикле 'foreach' в 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 char:8
+ foreach <<<< ($key in $myHash.keys){
+ CategoryInfo : InvalidOperation: (System.Collecti...tableEnumer
ator:HashtableEnumerator) [], RuntimeException
+ FullyQualifiedErrorId : BadEnumeration
Что дает и как мне решить эту проблему?
Ответы
Ответ 1
Вы не можете изменить Hashtable при перечислении. Это то, что вы можете сделать:
$myHash = @{}
$myHash["a"] = 1
$myHash["b"] = 2
$myHash["c"] = 3
$myHash = $myHash.keys | foreach{[email protected]{}}{$r[$_] = 5}{$r}
Изменить 1
Это проще для вас:
$myHash = @{}
$myHash["a"] = 1
$myHash["b"] = 2
$myHash["c"] = 3
foreach($key in $($myHash.keys)){
$myHash[$key] = 5
}
Ответ 2
Существует гораздо более простой способ достижения этого. Вы не можете изменить значение хеш-таблицы при его перечислении из-за того, что это переменная ссылочного типа. Это точно такая же история в .NET.
Используйте следующий синтаксис, чтобы обойти это. Мы преобразуем коллекцию ключей в базовый массив, используя нотацию @()
. Мы делаем копию коллекции ключей и вместо этого ссылаемся на этот массив, что означает, что теперь мы можем редактировать хеш-таблицу.
$myHash = @{}
$myHash["a"] = 1
$myHash["b"] = 2
$myHash["c"] = 3
foreach($key in @($myHash.keys)){
$myHash[$key] = 5
}
Ответ 3
Вам не нужно клонировать всю хеш-таблицу для этого примера. Достаточно просто перечислить коллекцию ключей, поместив ее в массив @(...)
:
foreach ($ key in @( $ myHash.keys )) {...
Ответ 4
Используйте clone
:
foreach($key in ($myHash.clone()).keys){
$myHash[$key] = 5
}
Или в одну строку:
$myHash = ($myHash.clone()).keys | % {} {$myHash[$_] = 5} {$myHash}
Ответ 5
Я новичок в PowerShell, но я очень люблю использовать встроенные функции, потому что считаю его более читаемым. Вот как я мог бы решить эту проблему, используя GetEnumerator и Clone. Этот подход также позволяет ссылаться на существующие хеш-значения (значение $_.) Для целей изменения.
$myHash = @{}
$myHash["a"] = 1
$myHash["b"] = 2
$myHash["c"] = 3
$myHash.Clone().GetEnumerator() | foreach-object {$myHash.Set_Item($_.key, 5)}
Ответ 6
Вы должны стать творческими!
$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
Ответ 7
Как упоминалось в предыдущем ответе, clone
- это путь. Мне нужно было заменить любые нулевые значения в хэше на "Неизвестно", и этот однострочный выполняет свою работу.
($record.Clone()).keys | %{if ($record.$_ -eq $null) {$record.$_ = "Unknown"}}
Ответ 8
$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
Ответ 9
$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
}
}
}
Обновление значения хеша, если элементы массива совпали с ключом хеша.
Ответ 10
Кажется, когда вы обновляете хеш-таблицу внутри цикла foreach, перечислитель делает себя недействительным. Я справился с этим, заполнив новую хеш-таблицу:
$myHash = @{}
$myHash["a"] = 1
$myHash["b"] = 2
$myHash["c"] = 3
$newHash = @{}
foreach($key in $myHash.keys){
$newHash[$key] = 5
}
$myHash = $newHash