鉴于我们不知道文件中键的名称,我试图在Json文件中查找所有通用键。
Json文件如下:
{
"DynamicKey1" : {
"foo" : 1,
"bar" : 2
},
"DynamicKey2" : {
"bar" : 3
},
"DynamicKey3" : {
"foo" : 5,
"zyx" : 5
}
}
预期结果:
{
"foo"
}
我试图在这里应用reduce / foreach逻辑,但是我不确定如何在jq中编写它。感谢您的帮助!
jq '. as $ss | reduce range(1; $ss|length) as $i ([]; . + reduce ($ss[i] | keys) as $key ([]; if $ss[$i - 1] | has($key) then . +$key else . end))' file.json
答案 0 :(得分:0)
在发布的Q中存在一些不一致之处:没有所有对象共有的键,并且如果查看键的成对相交,结果将同时包含“ foo”和“ bar”。 / p>
下面,我将针对这两个问题提出解决方案。
[.[] | keys_unsorted[]] | group_by(.)[] | select(length>1)[0]
这是使用类似方法的解决方案:
length as $length
| [.[] | keys_unsorted[]] | group_by(.)[]
| select(length==$length)
| .[0]
这涉及group_by/2
,它是使用排序实现的。
这里是一种替代方法,该方法依赖于内置函数keys
进行排序(关键是(((nk ln(nk))-n(k ln(k)))= nk ln(n),即具有n个小项的k个项比一个较大的n * k个项要好):
# The intersection of an arbitrary number of sorted arrays
def intersection_of_sorted_arrays:
# intersecting/1 returns a stream
def intersecting($A;$B):
def pop:
.[0] as $i
| .[1] as $j
| if $i == ($A|length) or $j == ($B|length) then empty
elif $A[$i] == $B[$j] then $A[$i], ([$i+1, $j+1] | pop)
elif $A[$i] < $B[$j] then [$i+1, $j] | pop
else [$i, $j+1] | pop
end;
[0,0] | pop;
reduce .[1:][] as $x (.[0]; [intersecting(.; $x)]);
要计算所有对象共有的键:
[.[] | keys] | intersection_of_sorted_arrays
答案 1 :(得分:0)
这里是一个无排序且省时的答案,它依赖于jq在JSON字典中实现查找的效率。由于键是字符串,因此我们可以简单地使用“单词袋”(bow
)的概念:
def bow(stream):
reduce stream as $word ({}; .[$word|tostring] += 1);
我们现在可以解决“所有对象共有的键”问题,如下所示:
length as $length
| bow(.[] | keys_unsorted[])
| to_entries[]
| select(.value==$length).key
同样,对于“多个对象中的键”问题。
当然,要实现时间效率,需要进行通常的时空权衡。
答案 2 :(得分:0)
或者,可以使用步行路径unix实用程序 jtc
分两步来实现相同的JSON操作:
bash $ <file.json jtc -w'<.*>L:<>k' -j | jtc -w'<.>Q:' -j
[
"bar",
"foo"
]
bash $
PS>披露:我是jtc
-用于JSON操作的shell cli工具的创建者