powershellscopegroup-object

PowerShell Group-Object no longer splitting objects into fixed-size collections


I had this in a script which I believe was working well, but appears to have stopped working:

$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

Previously Measure-Object would have given me a Count of 3, but now I receive a count of 1.

Why is this no longer working? Is the counter integer not being incremented within the Group-Object command anymore?


Solution

  • I don't think your command ever worked as intended (see the bottom section for details).

    Replace:

    { [math]::Floor($counter++ / $maxSize) }
    

    with:

    { [math]::Floor((Get-Variable -Scope 1 counter).Value++ / $maxSize) }
    

    in order to ensure that it is the caller's $counter variable that is updated across invocations of the script block.

    Note:


    The problem is that the script block passed to the (positionally) implied -Property parameter of Group-Object runs in a child scope, so that $counter++ implicitly creates a block-local variable on every invocation:

    Thus, in effect, the script block's return value is a fixed 0, so you'll only ever get one group.


    Alternatives to using Group-Object for "chunking":

    Your use of Group-Object to achieve "chunking" (batching, partitioning, i.e. splitting the input into arrays of fixed size) is elegant, but ultimately inefficient, and it isn't a streaming solution, because all input must be collected up front (neither aspect may matter in a given situation).