如果我有一个看起来像这样的 JSON 文件,则使用 jq-1.5
[{... ,"sapm_score":40.776, ...} {..., "spam_score":17.376, ...} ...]
我如何计算
sapm_score > 40
的数量?
谢谢, 丹
更新:
我查看了输入文件,格式实际上是
{... ,"sapm_score":40.776, ...}
{..., "spam_score":17.376, ...}
...
这会改变人们的计数方式吗?
[更新:如果输入不是数组,请参阅下面的最后一节。]
count/1
我建议定义一个
count
过滤器(也许将其放入 ~/.jq 中),也许如下所示:
def count(s): reduce s as $_ (0;.+1);
有了这个,假设输入是一个数组,你可以写:
count(.[] | select(.sapm_score > 40))
或者稍微更有效:
count(.[] | (.sapm_score > 40) // empty)
这种方法(计算流中的项目数)通常优于使用
length
,因为它避免了与构造数组相关的成本。
count/2
这是您可能喜欢使用的
count
的另一个定义(也可能添加到 ~/.jq 中):
def count(stream; cond): count(stream | cond // empty);
这会计算
cond
既不是 false
也不是 null
的流元素。
现在,假设输入由数组组成,您可以简单地编写:
count(.[]; .sapm_score > 40)
如果您想将“sapm_score”规范化为“spam_score”,那么(例如)您可以使用上面定义的
count/2
,如下所示:
count(.[]; .spam_score > 40 or .sapm_score > 40)
这假设数组中的所有项目都是 JSON 对象。如果情况并非如此,那么您可能需要尝试添加“?”键名后:
count(.[]; .spam_score? > 40 or .sapm_score? > 40)
当然,以上所有内容都假设输入是有效的 JSON。如果情况并非如此,请参阅 https://github.com/stedolan/jq/wiki/FAQ#processing-not-quite-valid-json
修改后的问题表明输入由 JSON 对象流组成(而最初输入被认为是 JSON 对象数组)。如果输入由 JSON 对象流组成,则可以轻松调整上述解决方案,具体取决于您拥有的 jq 版本。如果您的 jq 版本有
inputs
,则建议使用 (2)。
(1) 所有版本:使用
-s
命令行选项。
(2) 如果您的 jq 有
inputs
:使用 -n
命令行选项,并将上面的 .[]
更改为 inputs
,例如
count(inputs; .spam_score? > 40 or .sapm_score? > 40)
过滤满足条件的项,得到长度。
map(select(.sapm_score > 40)) | length
cat input.json | jq -c '. | select(.sapm_score > 40)' | wc -l
应该这样做。
-c
选项打印每场比赛的单行紧凑json表示,wc -l
计算jq打印的行数。
这是一种方法:
reduce .[] as $s(0; if $s.spam_score > 40 then .+1 else . end)
如果输入不是数组而是换行符分隔对象的序列(jsonlines)
reduce inputs as $s(0; if $s.spam_score > 40 then .+1 else . end)
如果使用 -n
标志调用 jq,则将起作用。这是一个例子:
$ cat data.json
{ "spam_score":40.776 }
{ "spam_score":17.376 }
$ jq -Mn 'reduce inputs as $s(0; if $s.spam_score > 40 then .+1 else . end)' data.json
1