如何用jq将数组拆分成块?

Ech*_*lan 12 arrays shell json memory-efficient jq

我有一个包含数组的非常大的JSON文件.是否可以使用jq将此数组拆分为几个固定大小的较小数组?假设我的输入是这样的:[1,2,3,4,5,6,7,8,9,10]我想把它分成3个元素的长块.所需的输出jq将是:

[1,2,3]
[4,5,6]
[7,8,9]
[10]
Run Code Online (Sandbox Code Playgroud)

实际上,我的输入数组有近300万个元素,都是UUID.

pea*_*eak 8

有一个(未记录的)内置,_nwise满足功能要求:

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

[1,2,3]
[4,5,6]
[7,8,9]
[10]
Run Code Online (Sandbox Code Playgroud)

也:

$ jq -nc '_nwise([1,2,3,4,5,6,7,8,9,10];3)' 
[1,2,3]
[4,5,6]
[7,8,9]
[10]
Run Code Online (Sandbox Code Playgroud)

顺便提一下,_nwise可以用于数组和字符串.

(我认为它没有记录,因为对某个名称有一些疑问.)

TCO版本

不幸的是,内置版本是粗心定义的,并且对大型数组不会很好.这是一个优化版本(它应该与非递归版本一样高效):

def nwise($n):
 def _nwise:
   if length <= $n then . else .[0:$n] , (.[$n:]|_nwise) end;
 _nwise;
Run Code Online (Sandbox Code Playgroud)

对于一个300万的数组,这是非常高性能:旧Mac上为3.91s,最大驻留大小为162746368.

请注意,此版本(使用尾调用优化递归)实际上比本页其他地方显示的nwise/2使用版本更快foreach.


pea*_*eak 4

以下面向流的 定义window/3,由 C\xc3\xa9dric Connes\n(github:connesc) 概括_nwise,\n并说明了\n“装箱技术”,该技术避免了使用流结束标记的需要,因此如果流包含非 JSON 值,\n则可以使用nan。还包括_nwise/1关于的定义。window/3

\n\n

的第一个参数window/3被解释为流。$size 是窗口大小,$step 指定要跳过的值的数量。例如,

\n\n
window(1,2,3; 2; 1)\n
Run Code Online (Sandbox Code Playgroud)\n\n

产量:

\n\n
[1,2]\n[2,3]\n
Run Code Online (Sandbox Code Playgroud)\n\n

窗口/3 和 _nsize/1

\n\n
def window(values; $size; $step):\n  def checkparam(name; value): if (value | isnormal) and value > 0 and (value | floor) == value then . else error("window \\(name) must be a positive integer") end;\n  checkparam("size"; $size)\n| checkparam("step"; $step)\n  # We need to detect the end of the loop in order to produce the terminal partial group (if any).\n  # For that purpose, we introduce an artificial null sentinel, and wrap the input values into singleton arrays in order to distinguish them.\n| foreach ((values | [.]), null) as $item (\n    {index: -1, items: [], ready: false};\n    (.index + 1) as $index\n    # Extract items that must be reused from the previous iteration\n    | if (.ready | not) then .items\n      elif $step >= $size or $item == null then []\n      else .items[-($size - $step):]\n      end\n    # Append the current item unless it must be skipped\n    | if ($index % $step) < $size then . + $item\n      else .\n      end\n    | {$index, items: ., ready: (length == $size or ($item == null and length > 0))};\n    if .ready then .items else empty end\n  );\n\ndef _nwise($n): window(.[]; $n; $n);\n
Run Code Online (Sandbox Code Playgroud)\n\n

来源:

\n\n

https://gist.github.com/connesc/d6b87cbacae13d4fd58763724049da58

\n