使用 jq 将对象数组转换为数组对象
Turn an array of objects into an object of arrays with jq
我想使用 jq
将对象数组转换为数组对象。
考虑我是否有以下两个文件:
file1.json:
{
"key1": 5,
"key2": 10
}
file2.json:
{
"key1": 2
}
我想把它们合并成:
{
"key1": [5, 2]
"key2": [10, null]
}
每个 jq
命令用一个字段很容易做到这一点,但我不知道如何一次用所有字段做到这一点。我的想法是,我需要将所有值转换为数组,然后将 reduce 与 *
一起使用,但我无法让它工作。
jq
命令需要对任意数量的文件(超过 2 个)起作用。
下面将按照您的描述将一个对象数组合并为一个对象(特别是,null用作填充符,如果例如每个输入对象被视为一个"observation"),但请注意,此处定义的 merge/0 不对输入对象中的键集做出任何假设,并且可能会根据可以做出的假设而变得更快。
def merge:
def allkeys: map(keys) | add | unique;
allkeys as $allkeys
| reduce .[] as $in ({};
reduce $allkeys[] as $k (.;
. + {($k): (.[$k] + [$in[$k]]) } ));
merge
现在使用 "slurp" 选项,例如:
$ jq -s -f merge.jq file*.json
这可能比@peak 的解决方案慢,但可能更容易阅读:
map(to_entries)
| flatten(1)
| group_by(.key)
| map({
key: .[0].key,
value: map(.value)})
| from_entries
像这样使用它:
jq -s 'map(to_entries) | flatten(1) | group_by(.key) | map({key: .[0].key, value: map(.value)}) | from_entries' file*.json
与您想要的输出不同,它不会用空值代替缺失值,如果 "null" 本身是一个有效值,这可能会有用。
这是另一个解决方案。
(add | keys) as $all # get all keys
| map( . as $o | reduce $all[] as $k ({}; .[$k] = $o[$k]) ) # normalize objects
| ( . as $a | reduce $all[] as $k ({}; .[$k] = ($a | map(.[$k]))) ) # transpose
到运行它使用-s
选项,例如:
$ jq -s -f filter.jq file1.json file2.json
示例输出:
{
"key1": [
5,
2
],
"key2": [
10,
null
]
}
如果您有更多文件,例如file3.json
{
"key3": 2
}
只需将它们添加到命令行
$ jq -s -f filter.jq file1.json file2.json file3.json
示例输出:
{
"key1": [
5,
2,
null
],
"key2": [
10,
null,
null
],
"key3": [
null,
null,
2
]
}
我想使用 jq
将对象数组转换为数组对象。
考虑我是否有以下两个文件:
file1.json:
{
"key1": 5,
"key2": 10
}
file2.json:
{
"key1": 2
}
我想把它们合并成:
{
"key1": [5, 2]
"key2": [10, null]
}
每个 jq
命令用一个字段很容易做到这一点,但我不知道如何一次用所有字段做到这一点。我的想法是,我需要将所有值转换为数组,然后将 reduce 与 *
一起使用,但我无法让它工作。
jq
命令需要对任意数量的文件(超过 2 个)起作用。
下面将按照您的描述将一个对象数组合并为一个对象(特别是,null用作填充符,如果例如每个输入对象被视为一个"observation"),但请注意,此处定义的 merge/0 不对输入对象中的键集做出任何假设,并且可能会根据可以做出的假设而变得更快。
def merge:
def allkeys: map(keys) | add | unique;
allkeys as $allkeys
| reduce .[] as $in ({};
reduce $allkeys[] as $k (.;
. + {($k): (.[$k] + [$in[$k]]) } ));
merge
现在使用 "slurp" 选项,例如:
$ jq -s -f merge.jq file*.json
这可能比@peak 的解决方案慢,但可能更容易阅读:
map(to_entries)
| flatten(1)
| group_by(.key)
| map({
key: .[0].key,
value: map(.value)})
| from_entries
像这样使用它:
jq -s 'map(to_entries) | flatten(1) | group_by(.key) | map({key: .[0].key, value: map(.value)}) | from_entries' file*.json
与您想要的输出不同,它不会用空值代替缺失值,如果 "null" 本身是一个有效值,这可能会有用。
这是另一个解决方案。
(add | keys) as $all # get all keys
| map( . as $o | reduce $all[] as $k ({}; .[$k] = $o[$k]) ) # normalize objects
| ( . as $a | reduce $all[] as $k ({}; .[$k] = ($a | map(.[$k]))) ) # transpose
到运行它使用-s
选项,例如:
$ jq -s -f filter.jq file1.json file2.json
示例输出:
{
"key1": [
5,
2
],
"key2": [
10,
null
]
}
如果您有更多文件,例如file3.json
{
"key3": 2
}
只需将它们添加到命令行
$ jq -s -f filter.jq file1.json file2.json file3.json
示例输出:
{
"key1": [
5,
2,
null
],
"key2": [
10,
null,
null
],
"key3": [
null,
null,
2
]
}