如何基于第二个值和第三个值的出现次数设置JSON值
初始如何基于第二个值和第三个值的出现次数设置JSON值,json,linux,bash,jq,Json,Linux,Bash,Jq,初始files.json文档状态: [ { "filename": "a", "dir": "foo", "type": "unknown" }, { "filename": "b", "dir": "foo", "type": "unknown" }, { "filename": "c", "dir": "bar", "type": "unknown" }, { "filename":
files.json
文档状态:
[
{
"filename": "a",
"dir": "foo",
"type": "unknown"
},
{
"filename": "b",
"dir": "foo",
"type": "unknown"
},
{
"filename": "c",
"dir": "bar",
"type": "unknown"
},
{
"filename": "a",
"dir": "bar",
"type": "unknown"
}
]
当“文件名”值在文档中仅出现一次时,“类型”值将仅取决于“目录”值:“dir”==“foo”->“type”=0
和“dir”==“bar”->“type”=1
当“foo”和“bar”目录中都存在“filename”值时,“type”的值必须等于2,如下所示:
[
{
"filename": "a",
"dir": "foo",
"type": "2"
},
{
"filename": "b",
"dir": "foo",
"type": "0"
},
{
"filename": "c",
"dir": "bar",
"type": "1"
},
{
"filename": "a",
"dir": "bar",
"type": "2"
}
]
“dir”值将始终限于“foo”或“bar”值的两个可能的备选值,并且永远不会为空。甚至“filename”值也会被设置,因为这些文件实际上是文件,所以在文档中最多只能出现两次 我希望通过在Linux中运行Bash脚本的JQ1.5(2015年8月16日稳定版)来实现这一点
jq '
([.[] | { (.filename): {(.dir): true} }] | reduce .[] as $item ({}; . * $item)) as $seen |
map(
if $seen[.filename]["foo"] and $seen[.filename]["bar"] then
.type = 2
elif $seen[.filename]["bar"] then
.type = 1
else
.type = 0
end
)
'
如果有助于理解其工作原理--
$seen
的值如下所示:
{
"a": {
"foo": true,
"bar": true
},
"b": {
"foo": true
},
"c": {
"bar": true
}
}
…这样,我们就可以方便地查看给定文件名使用过的目录条目
如果有助于理解其工作原理--
$seen
的值如下所示:
{
"a": {
"foo": true,
"bar": true
},
"b": {
"foo": true
},
"c": {
"bar": true
}
}
…因此,我们可以方便地查看给定文件名使用过的目录条目。一种方法是使用
group\u by
。在下面的例子中,group_by
被简单地使用,因此数组中最终结果的顺序由.filename决定;如果这不令人满意,可以使用相同的技术构造一个查找表,然后对原始数组使用该查找表
[group_by(.filename)[]
| (map(.dir)
| unique
| if length>1 then length
elif .[0] == "foo" then 0
elif .[0] == "bar" then 1
else .[0] # just in case
end) as $type
| (.[] + {type: $type} ) ]
输出
一种方法是使用
groupby
。在下面的例子中,group_by
被简单地使用,因此数组中最终结果的顺序由.filename决定;如果这不令人满意,可以使用相同的技术构造一个查找表,然后对原始数组使用该查找表
[group_by(.filename)[]
| (map(.dir)
| unique
| if length>1 then length
elif .[0] == "foo" then 0
elif .[0] == "bar" then 1
else .[0] # just in case
end) as $type
| (.[] + {type: $type} ) ]
输出
这里有一个类似于@CharlesDuffy的解决方案,但略短一些,更“jq-ish”: 使用
catalog/3
借助通用辅助函数catalog/3
:
def catalog(s; keyp; valuep):
reduce s as $x ({}; (.[$x|keyp|tostring]) += [$x|valuep]);
解决方案变得更具可读性:
(catalog(.[]; .filename; .dir) | map_values(unique)) as $dirs
| map( $dirs[.filename] as $d
| .type |= if $d|length > 1 then 2
elif $d[0] == "bar" then 1
else 0
end)
这里有一个类似于@CharlesDuffy的解决方案,但略短一些,更“jq-ish”: 使用
catalog/3
借助通用辅助函数catalog/3
:
def catalog(s; keyp; valuep):
reduce s as $x ({}; (.[$x|keyp|tostring]) += [$x|valuep]);
解决方案变得更具可读性:
(catalog(.[]; .filename; .dir) | map_values(unique)) as $dirs
| map( $dirs[.filename] as $d
| .type |= if $d|length > 1 then 2
elif $d[0] == "bar" then 1
else 0
end)
@peak:事实上,文档有一个优先排序,它不是基于我希望能够保留的“文件名”,尽管这个过滤器仍然运行良好。但还有你的第二个解决方案,就像一首诗一样美丽。。。。我还有多少东西要学@peak:事实上,文档有一个优先排序,它不是基于我希望能够保留的“文件名”,尽管这个过滤器仍然运行良好。但还有你的第二个解决方案,就像一首诗一样美丽。。。。我还有多少东西要学!谢谢你,查尔斯,这是个好办法!是你激发了peak的第二个建议,它成为了我的最爱,因为它对我来说更“强大”;例如,as is不依赖于当前的“type”值,与这里不同(尽管我相信,在这里也可以很容易地获得)…如果您不想只更改当前
类型为未知的,那么只需删除If
。谢谢@Charles,这是一个很好的解决方案!是你激发了peak的第二个建议,它成为了我的最爱,因为它对我来说更“强大”;例如,as is不依赖于当前的“type”值,与这里不同(尽管我相信,在这里也可以很容易地获得)…如果您不想只更改当前类型为未知的,那么只需删除If
。在我看来,这是一个完美的解决方案,在我看来,这似乎是一个完美的解决方案,一个让自己易于阅读和理解,并且工作出色的解决方案。