Home > OS >  How to chunk items from pipeline in PowerShell?
How to chunk items from pipeline in PowerShell?

Time:04-06

in my PowerShell cmdlet I get an arbitrary number of items via pipeline and want to return chunks of a specified number of items.

When, for example, my script gets as input:

("A", "B", "C", "D", "E", "F", "G")

And I define, let's say 4 as chunk size, I'd like to return something like this:

(
    ("A", "B", "C", "D"),
    ("E", "F", "G")
)

Any help would be appreciated.

CodePudding user response:

You can write a simple function that buffers N input objects before spitting out a new array, then output any buffered values you might have left over when you reach the end of the input sequence:

function chunk {
  param(
    [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
    [psobject]$InputObject,

    [ValidateRange(1, 100000)]
    [int]$ChunkSize = 4
  )

  begin {
    $counter = 0
    # Set up array that will act as buffer
    $chunk = [object[]]::new($ChunkSize)
  }

  process {
    # Add input object to next available slot in array
    $chunk[$counter  ] = $InputObject

    if($counter -eq $ChunkSize){
        # If we've filled the buffer, output it as a new chunk
      Write-Output $chunk -NoEnumerate

      # Reset counter and buffer
      $counter = 0
      $chunk = [object[]]::new($ChunkSize)
    }
  }

  end {
    if($counter){
      # There's no more input but we have some data left over still, output it 
      Write-Output $chunk[0..($counter-1)] -NoEnumerate
    }
  }
}

Now you can do:

PS ~> $firstChunk,$nextChunk = "A", "B", "C", "D", "E", "F", "G" |chunk
PS ~> $firstChunk
A
B
C
D
PS ~> $nextChunk
E
F
G

CodePudding user response:

If I could save it to a file first, it could work using get-content's -readcount parameter. I couldn't keep the 2 lists wrapped with regular arrays and =, so I used an arraylist, hiding the output of arraylist.add(). I wish you could do named pipes on the fly like in zsh.

echo A B C D E F G | set-content file    # PS7:  'A'..'G'
get-content file -ReadCount 4 | 
  % { [collections.arraylist]$list = @() } { $list.add($_) > $null }


$list[0]

A
B
C
D


$list[1]

E
F
G
  • Related