2

Sample Input

[1,2,3,4,5,6,7,8,9]

My Solution

$ echo '[1,2,3,4,5,6,7,8,9]' | jq --arg g 4 '. as $l|($g|tonumber) as $n |$l|length as $c|[range(0;$c;($g|tonumber))]|map($l[.:.+$n])' -c

Output

[[1,2,3,4],[5,6,7,8],[9]]

shorthand, handy method anything else?

App-Club
  • 41
  • 1
  • 1
  • 4
  • 1
    There are some answers at https://stackoverflow.com/questions/51412721/how-to-split-an-array-into-chunks-with-jq – peak Mar 24 '22 at 01:44

3 Answers3

2

Use a while loop to chop off the first 4 elements .[4:] until the array is empty []. Then, for each result array, consider only its first 4 items [:4]. Generalized to $n:

jq -c --argjson n 4 '[while(. != []; .[$n:])[:$n]]'
[[1,2,3,4],[5,6,7,8],[9]]

Demo

pmf
  • 24,478
  • 2
  • 22
  • 31
1

One way using reduce operating on the whole list, forming only n entries (sub-arrays) at a time

jq -c --argjson g 4 '. as $input | 
  reduce range(0; ( $input | length ) ; $g) as $r ( []; . + [ $input[ $r: ( $r + $g ) ] ] )'

The three argument form of range(from: upto; by) generates numbers from to upto with an increment of by

E.g. range(0; 9; 4) from your original input produces a set of indices - 0, 4, 8 which is ranged over and the final list is formed by appending the slices, coming out of the array slice operation e.g. [0:4], [4:8] and [8:12]

Inian
  • 80,270
  • 14
  • 142
  • 161
  • 2
    Instead of having `reduce` successively build up the array, you could also directly collect the fragments in a superordinate array, which would render unnecessary saving the input in a variable: `jq --argjson g 4 '[range(0; length; $g) as $r | .[$r:$r+$g]]'` – pmf Mar 23 '22 at 22:10
  • @pmf I like using `reduce`, but yeah the above is much shorter. Thanks – Inian Mar 24 '22 at 04:08
1

There's an undocumented builtin function, _nwise/1, which you would use like this:

jq -nc --argjson n 4 '[1,2,3,4,5,6,7,8,9] | [_nwise($n)]'

[[1,2,3,4],[5,6,7,8],[9]]

Notice that using --argjson allows you to avoid the call to tonumber.

peak
  • 105,803
  • 17
  • 152
  • 177