PowerShell Group-Object больше не разбивает объекты на коллекции фиксированного размера.
У меня было это в сценарии, который, как мне кажется, работал хорошо, но, похоже, перестал работать:
$testList = @("object 1","object 2","object 3","object 4","object 5")
$counter = 0
$maxSize = 2
$groupedList = $testList | Group-Object { [math]::Floor($counter++ / $maxSize) }
$groupedList
$groupedList | Measure-Object
Раньше Measure-Object дал бы мне количество 3, но теперь я получаю количество 1.
Почему это больше не работает? Целое число счетчика больше не увеличивается в команде Group-Object?
1 ответ
Я не думаю, что ваша команда когда-либо работала должным образом (подробности см. В нижнем разделе).
Заменять:
{ [math]::Floor($counter++ / $maxSize) }
с:
{ [math]::Floor((Get-Variable -Scope 1 counter).Value++ / $maxSize) }
чтобы гарантировать, что это переменная вызывающего объекта, которая обновляется при вызовах блока скрипта.
Примечание:
$script:counter++
тоже работает, но только если область вызова является областью верхнего уровня скрипта.Get-Variable
-Scope 1 counter
явно нацелен на определение родительской области , которое является вызывающим; для краткости можно опустить-Scope 1
, потому что по умолчанию возвращается переменная в ближайшей наследственной области.Сантьяго Скуарзон предлагает другой вариант: Вы можете определить свою переменную как объект ссылочного типа со свойством, а не как целое число, в простейшей форме как
хеш -таблицу : $counter = @{ Value = 0 }
Благодаря тому, что теперь он содержит ссылку на объект, дочерняя область в блоке скрипта видит тот же самый объект при запросе значения переменной родительской области и может обновлять его.
.Value
имущество:{ [math]::Floor($counter.Value++ / $maxSize) }
Проблема в том, что блок сценария передается (позиционно) подразумеваемому
-Property
параметр
То есть,
$counter++
не действует на существующую переменную в родительской области; он неявно создает локальную копию переменной (с текущим значением вызывающего объекта) и применяется к ней .Это, возможно, удивительное поведение — локальная переменная неявно создается при (якобы) назначении переменной, которая существует в наследственной области — подробно обсуждается в
этом ответе . В связи с этим может показаться удивительным, что такой блок скрипта (который в целом включает в себя вычисляемые свойства) выполняется в дочерней области, а не непосредственно в вызывающей области для начала — см.
GitHub issue #7157 .
Поскольку ваш
++
является постинкрементом, это исходное значение (скопированное из переменной родительской области), которое действует как операнд LHS для операции деления/
.При выходе из блока скрипта локальный
$counter
переменная выходит за пределы области видимости, и следующий вызов начинается с нуля.
Таким образом, фактически возвращаемое значение блока скрипта является фиксированным.
0
, так что вы получите только одну группу.
Альтернативы использованию для «дробления» :
Ваше использование
Group-Object
для достижения «фрагментации» (объединения, разбиения, т. е. разделения ввода на массивы фиксированного размера) элегантно, но в конечном счете неэффективно, и это не потоковое решение, потому что весь ввод должен быть собран заранее (ни один из аспектов может не иметь значения в заданная ситуация).
Было бы здорово, если бы
Select-Object
напрямую поддерживает такую функцию, которую предлагаетGitHub issue #8270 , в виде -ReadCount
параметр:# WISHFUL THINKING PS> 1..5 | Select-Object -ReadCount 2 | ForEach-Object { "$_" } 1 2 3 4 5
Этот ответ предоставляет пользовательскую функцию, Select-Chunk
, который реализует этот функционал:# Assumes function Select-Chunk from the linked answer is defined. PS> 1..5 | Select-Chunk -ReadCount 2 | ForEach-Object { "$_" } 1 2 3 4 5