jq:groupby和嵌套的json数组

时间:2019-05-17 03:46:14

标签: json group-by jq data-partitioning

假设我有:[[1,2], [3,9], [4,2], [], []]

我想知道要获取的脚本:

  • 不是非空的嵌套列表的数量。即想得到:[3,2]

  • 包含或不包含数字3的嵌套列表的数量。即,要获取:[1,4]

  • 其元素的总和不小于4的嵌套列表的数量。即想得到:[3,2]

即嵌套数据分区的基本示例。

1 个答案:

答案 0 :(得分:1)

由于stackoverflow.com不是编码服务,因此我将对第一个问题的回答仅限于此,希望它可以说服您学习jq是值得的。

让我们首先完善有关列表计数的问题 “不为空”将强调答案中的第一个数字应与空列表的数量(2)相对应,而第二个数字应与其余的列表(3)相对应。也就是说,所需答案应为[2,3]

使用内置过滤器的解决方案

下一步可能是询问是否可以使用group_by。如果顺序无关紧要,我们可以简单地写:

group_by(length==0) | map(length)

这返回[3,2],这不是我们想要的。现在值得检查有关group_by应该做什么的文档。在查看https://stedolan.github.io/jq/manual/#Builtinoperatorsandfunctions上的详细信息时, 我们看到,group_by确实确实按分组值排序。

自从jq false < true开始,我们可以通过编写以下内容来修正我们的首次尝试:

group_by(length > 0) | map(length)

这很好,但是由于group_by所做的工作量很大,而我们真正需要的只是一种计数方法,因此很显然,我们应该能够提出一个更有效(并且希望更少不透明)的解决方案。

有效的解决方案

从根本上讲,问题可以归结为计数,因此让我们定义一个通用的tabulate过滤器以产生不同字符串值的计数。这是一个足以满足当前目的的定义:

# Produce a JSON object recording the counts of distinct
# values in the given stream, which is assumed to consist 
# solely of strings.
def tabulate(stream):
  reduce stream as $s ({}; .[$s] += 1);

现在只需两行就可以写下一个有效的解决方案:

tabulate(.[] | length==0 | tostring )
| [.["true", "false"]]

QED

p.s。

上面名为tabulate的函数有时称为bow(用于“单词袋”)。在某些方面,这将是一个更好的名称,尤其是将tabulate保留为适用于任意流的类似功能是很有意义的。