Select 个条目基于 jq 中的多个值
Select entries based on multiple values in jq
我正在与 JQ 合作,到目前为止我非常喜欢它。我 运行 遇到了一个问题,但我还没有在其他任何地方找到解决方案,我想看看社区是否有办法解决这个问题。
假设我们有一个 JSON 文件,如下所示:
{"author": "Gary", "text": "Blah"}
{"author": "Larry", "text": "More Blah"}
{"author": "Jerry", "text": "Yet more Blah"}
{"author": "Barry", "text": "Even more Blah"}
{"author": "Teri", "text": "Text on text on text"}
{"author": "Bob", "text": "Another thing to say"}
现在,我们想要 select 行,其中 author
的值等于 "Gary" 或 "Larry",但没有其他情况。实际上,我要检查的名称有数千个,因此简单地说明直接名称或条件名称(例如 cat blah.json | jq -r 'select(.author == "Gary" or .author == "Larry")'
)是不够的。我正在尝试通过 inside
函数来执行此操作,但出现错误对话框:
cat blah.json | jq -r 'select(.author | inside(["Gary", "Larry"]))'
jq: error (at <stdin>:1): array (["Gary","La...) and string ("Gary") cannot have their containment checked
执行此类操作的最佳方法是什么?
IRC 用户 gnomon 在 jq channel 上的回答如下:
jq 'select([.author] | inside(["Larry", "Garry", "Jerry"]))'
正如用户所说,这种方法背后的直觉是:"Literally your idea, only wrapping .author
as [.author]
to coerce it into being a single-item array so inside()
will work on it."这个答案产生了过滤列表中提供的一系列名称的预期结果,作为原始问题所需。
您可以像设置对象一样使用对象来测试成员资格。对数组进行操作的方法效率低下,尤其是在数组可能很大的情况下。
您可以在读取您的输入之前建立一组值,然后使用该组来过滤您的输入。
$ jq -n --argjson names '["Larry","Garry","Jerry"]' '
(reduce $names[] as $name ({}; .[$name] = true)) as $set
| inputs | select($set[.author])
' blah.json
inside
和 contains
有点奇怪。这里有一些更直接的解决方案:
index/1
select( .author as $a | ["Gary", "Larry"] | index($a) )
any/2
["Gary", "Larry"] as $whitelist
| select( .author as $a | any( $whitelist[]; . == $a) )
使用字典
如果性能是个问题,并且 "author" 始终是一个字符串,那么应该考虑按照@JeffMercado 建议的解决方案。这是一个变体(与 -n 命令行选项一起使用):
["Gary", "Larry"] as $whitelist
| ($whitelist | map( {(.): true} ) | add) as $dictionary
| inputs
| select($dictionary[.author])
我正在与 JQ 合作,到目前为止我非常喜欢它。我 运行 遇到了一个问题,但我还没有在其他任何地方找到解决方案,我想看看社区是否有办法解决这个问题。
假设我们有一个 JSON 文件,如下所示:
{"author": "Gary", "text": "Blah"}
{"author": "Larry", "text": "More Blah"}
{"author": "Jerry", "text": "Yet more Blah"}
{"author": "Barry", "text": "Even more Blah"}
{"author": "Teri", "text": "Text on text on text"}
{"author": "Bob", "text": "Another thing to say"}
现在,我们想要 select 行,其中 author
的值等于 "Gary" 或 "Larry",但没有其他情况。实际上,我要检查的名称有数千个,因此简单地说明直接名称或条件名称(例如 cat blah.json | jq -r 'select(.author == "Gary" or .author == "Larry")'
)是不够的。我正在尝试通过 inside
函数来执行此操作,但出现错误对话框:
cat blah.json | jq -r 'select(.author | inside(["Gary", "Larry"]))'
jq: error (at <stdin>:1): array (["Gary","La...) and string ("Gary") cannot have their containment checked
执行此类操作的最佳方法是什么?
IRC 用户 gnomon 在 jq channel 上的回答如下:
jq 'select([.author] | inside(["Larry", "Garry", "Jerry"]))'
正如用户所说,这种方法背后的直觉是:"Literally your idea, only wrapping .author
as [.author]
to coerce it into being a single-item array so inside()
will work on it."这个答案产生了过滤列表中提供的一系列名称的预期结果,作为原始问题所需。
您可以像设置对象一样使用对象来测试成员资格。对数组进行操作的方法效率低下,尤其是在数组可能很大的情况下。
您可以在读取您的输入之前建立一组值,然后使用该组来过滤您的输入。
$ jq -n --argjson names '["Larry","Garry","Jerry"]' '
(reduce $names[] as $name ({}; .[$name] = true)) as $set
| inputs | select($set[.author])
' blah.json
inside
和 contains
有点奇怪。这里有一些更直接的解决方案:
index/1
select( .author as $a | ["Gary", "Larry"] | index($a) )
any/2
["Gary", "Larry"] as $whitelist
| select( .author as $a | any( $whitelist[]; . == $a) )
使用字典
如果性能是个问题,并且 "author" 始终是一个字符串,那么应该考虑按照@JeffMercado 建议的解决方案。这是一个变体(与 -n 命令行选项一起使用):
["Gary", "Larry"] as $whitelist
| ($whitelist | map( {(.): true} ) | add) as $dictionary
| inputs
| select($dictionary[.author])