使用 jq 对象和数组组合 json 个文件
Combining json files using jq objects with array
我试过使用
jq "reduce inputs.skins as $s (.; .skins += $s)" file1.json file2.json > combined.json
但它只是从每个文件
创建了两个boots.name和fun.name
有什么方法可以使用 jq 并组合对象和数组而不会重复?
对于任何混淆,我深表歉意,jq有点复杂,要找到一个简单的教程让我理解
file1.json
{
"skins": [
{
"Item Shortname": "boots.name",
"skins": [
2,
25,
41,
]
},
{
"Item Shortname": "fun.name",
"skins": [
12,
8,
]
}
]
}
file2.json
{
"skins": [
{
"Item Shortname": "boots.name",
"skins": [
2,
20,
]
},
{
"Item Shortname": "fun.name",
"skins": [
90,
6,
82,
]
}
]
}
combined.json
{
"skins": [
{
"Item Shortname": "boots.name",
"skins": [
2,
20,
25,
41,
]
},
{
"Item Shortname": "fun.name",
"skins": [
90,
6,
82,
12,
8,
]
}
]
}
这里棘手的部分是满足明显的唯一性要求,为此可以使用以下通用过滤器:
# emit a stream of the distinct items in `stream`
def uniques(stream):
foreach stream as $s ({};
($s|type) as $t
| (if $t == "string" then $s else ($s|tostring) end) as $y
| if .[$t][$y] then .emit = false else .emit = true | (.item = $s) | (.[$t][$y] = true) end;
if .emit then .item else empty end );
这样可以确保保留顺序。这有点棘手,因为它是完全通用的——它允许 1
和 "1"
并区分它们,就像 unique
所做的那样。
(如果顺序无关紧要,则可以使用 unique
。)
因此,假设按照
行进行调用
jq -s -f program.jq file1.json file2.json
你可以在 program.jq 中放置上面的 def 和下面的“主”程序:
.[0] as $file1 | .[1] as $file2
| (INDEX($file1.skins[]; .["Item Shortname"]) | map_values(.skins)) as $dict
| $file2
| .skins |= map( .["Item Shortname"] as $name
| .skins += $dict[$name]
| .skins |= [uniques(.[])] )
更好的解决方案是避免使用 -s 选项(例如如下所示),但上述将两个文件提供给 jq 的方法至少是直接的,并且无论您使用的是哪个版本的 jq 都可以使用。
解决方案使用input
避免吞噬这两个文件的一种方法是将 input
与 -n 命令行选项而不是 -s 结合使用。 jq 程序的“主要”部分如下所示:
(INDEX(input.skins[]; .["Item Shortname"]) | map_values(.skins)) as $dict
| input
| .skins |= map( .["Item Shortname"] as $name
| .skins += $dict[$name]
| .skins |= [uniques(.[])] )
我试过使用
jq "reduce inputs.skins as $s (.; .skins += $s)" file1.json file2.json > combined.json
但它只是从每个文件
创建了两个boots.name和fun.name有什么方法可以使用 jq 并组合对象和数组而不会重复?
对于任何混淆,我深表歉意,jq有点复杂,要找到一个简单的教程让我理解
file1.json
{
"skins": [
{
"Item Shortname": "boots.name",
"skins": [
2,
25,
41,
]
},
{
"Item Shortname": "fun.name",
"skins": [
12,
8,
]
}
]
}
file2.json
{
"skins": [
{
"Item Shortname": "boots.name",
"skins": [
2,
20,
]
},
{
"Item Shortname": "fun.name",
"skins": [
90,
6,
82,
]
}
]
}
combined.json
{
"skins": [
{
"Item Shortname": "boots.name",
"skins": [
2,
20,
25,
41,
]
},
{
"Item Shortname": "fun.name",
"skins": [
90,
6,
82,
12,
8,
]
}
]
}
这里棘手的部分是满足明显的唯一性要求,为此可以使用以下通用过滤器:
# emit a stream of the distinct items in `stream`
def uniques(stream):
foreach stream as $s ({};
($s|type) as $t
| (if $t == "string" then $s else ($s|tostring) end) as $y
| if .[$t][$y] then .emit = false else .emit = true | (.item = $s) | (.[$t][$y] = true) end;
if .emit then .item else empty end );
这样可以确保保留顺序。这有点棘手,因为它是完全通用的——它允许 1
和 "1"
并区分它们,就像 unique
所做的那样。
(如果顺序无关紧要,则可以使用 unique
。)
因此,假设按照
行进行调用jq -s -f program.jq file1.json file2.json
你可以在 program.jq 中放置上面的 def 和下面的“主”程序:
.[0] as $file1 | .[1] as $file2
| (INDEX($file1.skins[]; .["Item Shortname"]) | map_values(.skins)) as $dict
| $file2
| .skins |= map( .["Item Shortname"] as $name
| .skins += $dict[$name]
| .skins |= [uniques(.[])] )
更好的解决方案是避免使用 -s 选项(例如如下所示),但上述将两个文件提供给 jq 的方法至少是直接的,并且无论您使用的是哪个版本的 jq 都可以使用。
解决方案使用input
避免吞噬这两个文件的一种方法是将 input
与 -n 命令行选项而不是 -s 结合使用。 jq 程序的“主要”部分如下所示:
(INDEX(input.skins[]; .["Item Shortname"]) | map_values(.skins)) as $dict
| input
| .skins |= map( .["Item Shortname"] as $name
| .skins += $dict[$name]
| .skins |= [uniques(.[])] )