如何递归查找对象中的所有数组并将它们缩减为第一项?
我尝试使用if .[0]? == "" then .[0] else . end
检测数组,但如果当前对象不是数组,则不输出任何内容。
输入:
{
"a": 1,
"b": [
1,
2,
3
],
"c": [
{
"a": 1,
"b": [
1,
2,
3
],
"c": {
"a": 1,
"b": [
1,
2,
3
]
}
},
{
"a": 1,
"b": [
1,
2,
3
],
"c": {
"a": 1,
"b": [
1,
2,
3
]
}
},
{
"a": 1,
"b": [
1,
2,
3
],
"c": {
"a": 1,
"b": [
1,
2,
3
]
}
}
]
}
输出:
{
"a": 1,
"b": [
1
],
"c": [
{
"a": 1,
"b": [
1
],
"c": {
"a": 1,
"b": [
1
]
}
}
]
}
答案 0 :(得分:1)
walk / 1包含在jq的最新版(1.5版)中。它也可以在下面找到。
以下是如何根据我的理解实现您的目标:
walk(if type == "array" and length > 1 then [.[0]] else . end)
# Apply f to composite entities recursively, and to atoms
def walk(f):
. as $in
| if type == "object" then
reduce keys[] as $key
( {}; . + { ($key): ($in[$key] | walk(f)) } ) | f
elif type == "array" then map( walk(f) ) | f
else f
end;
答案 1 :(得分:1)
我提出的天真解决方案是(.. | arrays) |= .[0]
,但这不起作用,因为递归是从外部完成的,这意味着在嵌套的情况下,我们最终试图从值中获取。[0]谁不再是阵列。
这可以通过进行后序遍历来解决,如in this GitHub issue所述。
使用post_recurse
,只需在上述天真解决方案中将..
替换为post_recurse
即可。完整的解决方案:
def post_recurse(f): def r: (f | select(. != null) | r), .; r; def post_recurse: post_recurse(.[]?); (post_recurse | arrays) |= .[0]
答案 2 :(得分:0)
以下是使用 tostream 转换输入对象的解决方案 进入路径流,过滤掉具有非零数组索引的任何路径 并使用 reduce 和 setpath 将结果转换回对象。所有递归都是 tostream 的内部。
[
tostream
| if length != 2 then empty
elif ([.[0][]|numbers|.!=0]|any) then empty
else .
end
]
| reduce .[] as $p (
{};
setpath($p[0]; $p[1])
)