求助:使用JQ筛选并删除嵌套数组含重复项的JSON对象
JQ筛选保留含不同条目的数组对象问题
问题说明
给定JSON数组,需删除所有ratings.q1.all_answers数组元素全重复的顶层对象,仅保留该数组至少包含两种不同元素的对象。
示例输入JSON:
[ { "ratings" : { "q1" : { "all_answers" : [ "a", "a", "a" ], "top_answer" : "a" }, "q2" : { "all_answers" : [ "no", "yes", "yes" ], "top_answer" : "yes" } }, { "ratings" : { "q1" : { "all_answers" : [ "a", "b", "b" ], "top_answer" : "a" }, "q2" : { "all_answers" : [ "no", "yes", "yes" ], "top_answer" : "yes" } }, { "ratings" : { "q1" : { "all_answers" : [ "a", "b", "c" ], "top_answer" : "a" }, "q2" : { "all_answers" : [ "no", "yes", "yes" ], "top_answer" : "yes" } } ]
用户尝试以下命令但无效果:
jq '.[] |= select(.ratings.q1.all_answers | length as $len | $len > ($len - (. | unique | length)))'
问题原因
- 逻辑判断错误:原命令中的条件
$len > ($len - (. | unique | length))化简后等价于unique数组长度 > 0,所有非空数组都满足该条件,因此所有对象都被保留。 - 数组修改方式错误:
.[] |= select(...)会将不符合条件的元素设为null而非直接删除,导致数组仍保留这些无效元素。
正确解决方案
以下几种写法均可实现需求:
方案1:通过去重后数组长度判断
判断去重后的数组长度是否大于1(即原数组至少有两种不同元素),用map(select(...))过滤数组:
jq 'map(select(.ratings.q1.all_answers | unique | length > 1))'
方案2:对比原数组与去重后数组长度
通过原数组长度和去重后长度的关系,确认存在不同元素:
jq 'map(select(.ratings.q1.all_answers | (length as $orig_len | unique | length) > 1))'
方案3:检查是否存在与第一个元素不同的元素
利用any()函数判断数组中是否有元素不等于第一个元素,以此确认不全为重复值:
jq 'map(select(.ratings.q1.all_answers | any(. != first)))'
以上命令都会过滤掉q1.all_answers全为重复值的对象,仅保留符合要求的条目。
内容的提问来源于stack exchange,提问作者JQamateur
相关产品推荐
相关产品推荐

