Powershell получает в цикле счетчик - PullRequest
2 голосов
/ 06 апреля 2019

Я пытаюсь получить перечислитель при зацикливании хеш-таблицы.

Я понимаю, как это работает в цикле foreach, как показано ниже:

$test = @{set01 = '0'; set02 = '1'}
foreach ($t in $test.GetEnumerator()) {
    Write-Host 'key: '$t.Key
}

Что выдаст отдельный ключ для цикла:

key:  set02
key:  set01

Я хотел бы знать, возможно ли это сделать в цикле типа C, например:

$test = @{set01 = '0'; set02 = '1'}
for ($i = 0; $i -lt 1; $i++) {
    Write-Host 'key: '$test.Keys[$i] # edited with Dandré's answer.
}

В котором перечислены все ключи:

key:  set02 set01
key:  

Возможно ли это или .GetEnumerator() работает только в ситуации foreach?

edit: Reading mklement0's answer Я вижу, что это невозможно напрямую. Я отмечу это как ответ для подробного объяснения.

Один обходной путь, который я нашел для извлечения ключа для позиции цикла, частично связан с ответом Дандре в сочетании с объяснением mklement0.

Если ключи собраны в массив до запуска цикла, их можно посмотреть во время выполнения цикла for.

$test = @{set01 = '0'; set02 = '1'}

$keys = @($test.Keys)

for ($i = 0; $i -lt $test.Count; $i++) {
    Write-Host 'key:'$keys[$i]
}

Это приведет к ожидаемому результату:

key: set02
key: set01

в зависимости от массива сначала необходимо изменить ключи [array]::Reverse($keys).

Переменная $keys также может использоваться в цикле для вызова определенных ключей, как в: $test[$keys[$i]]. Это что-то вроде хака, но открывает некоторые интересные возможности.

Ответы [ 2 ]

3 голосов
/ 06 апреля 2019

Согласен с @ mklement0. Если вы хотите использовать традиционный for -loop, вы можете сделать следующее, используя свойство Keys.

$test = @{set01 = '0'; set02 = '1'}

for ($i = 0; $i -lt $test.Count; $i++) {
    Write-Host $test.Keys[$i]
}

Будет выведено: set02 set01

2 голосов
/ 06 апреля 2019

Вы создаете хеш-таблицу , записи которой не доступны с позиционными индексами (0, 1, ...); вместо того, что вы указываете внутри [...], это запись key .

Поэтому для перечисления используйте свойство .Keys:

$test = @{set01 = '0'; set02 = '1'}
foreach ($key in $test.Keys) {
  $key 
  # To access the entry's *value*, use $test[$key] $test[$key]
}

Результат:

set02
set01

Обратите внимание, что ключи были перечислены в другом порядке, чем они были определены, потому что [hashtable] экземпляры не гарантируют какой-либо конкретный порядок перечисления.

В PSv3 + вы можете использовать упорядоченную хеш-таблицу , чтобы исправить это, что также позволит вам использовать позиционную индексацию - но учтите, что позиционная индексация затем возвращает запись значений , а не ключи:

$test = [ordered] @{set01 = '0'; set02 = '1'}
for ($i = 0; $i -lt $test.Count; $i++) {
  $test[$i]
}

Примечание: хотя вы могли бы использовать $test.Keys[$i] для доступа к клавишам, как в ответ Дандре , прямое перечисление клавиш с помощью foreach ($key in $test.Keys) менее многословно и быстрее; единственная веская причина для использования итерации на основе индекса с $test.Keys[$i] была бы, если бы индекс $i был не просто переменной helper , а требовался для работы, например, для вывода строки, отражающей оба ключ и его индекс.

Таким образом, приведенное выше дает:

0
1

Обратите внимание, что синтаксис for не только многословен, он фактически работает хуже, чем foreach и , если вам нужны явные индексы, используйте foreach с сгенерированными индексами через оператор диапазона (..) , который не только быстрее, но и, возможно, более читабелен, чем цикл for:

$test = [ordered] @{set01 = '0'; set02 = '1'}
foreach ($i in 0..($test.Count-1)) {
   $test[$i]
}

Несмотря на то, что он менее эффективен в отношении памяти, поскольку массив индексов должен быть создан как единое целое, это обычно не имеет значения.

...