如何在任意结构JSON中递归统计指定值的出现次数?
递归统计任意JSON结构中指定值的出现次数
现有实现
我已经找到一种统计任意结构JSON中值出现次数的方法,代码如下:
{ cat <<EOF { "a": 3, "b": 4, "c": 3, "d": { "e": 3 }, "f": 6 } EOF } | jq '[.. | if type == "object" then select(.value) else . end ] | map(select(. == 3)) | length'
问题
是否存在更简洁的方式来递归统计任意结构JSON中指定值的出现次数?我尝试使用walk函数,但仅写出如下代码,无法完成最终统计:
{ cat <<EOF { "a": 3, "b": 4, "c": 3, "d": { "e": 3 }, "f": 6 } EOF } | jq '.. | walk(if type == "object" then to_entries | map(select(.value)) | from_entries else . end ) | (. == 3)'
执行后得到结果:
false true false true false true false
更简洁的实现方案
方案1:.. + reduce(最简洁高效)
直接遍历所有递归节点,用reduce累加符合条件的次数,无需构造中间数组:
{ cat <<EOF { "a": 3, "b": 4, "c": 3, "d": { "e": 3 }, "f": 6 } EOF } | jq 'reduce .. as $item (0; if $item == 3 then . + 1 else . end)'
方案2:简化数组筛选方式
原方法可以去掉对object的冗余判断,因为..会自动展开所有嵌套节点(包括object的每个值),直接筛选目标值即可:
{ cat <<EOF { "a": 3, "b": 4, "c": 3, "d": { "e": 3 }, "f": 6 } EOF } | jq '[.. | select(. == 3)] | length'
方案3:正确使用walk函数
利用walk递归遍历节点,收集所有符合条件的值后统计数量:
{ cat <<EOF { "a": 3, "b": 4, "c": 3, "d": { "e": 3 }, "f": 6 } EOF } | jq '[walk(if . == 3 then . else empty end)] | length'
内容的提问来源于stack exchange,提问作者Zelphir Kaltstahl
相关产品推荐
相关产品推荐

