如何使用 jq 按元素 属性 值过滤对象数组?
How to filter array of objects by element property values using jq?
我喜欢使用 jq:
过滤 json 个文件
jq . some.json
假设 json 包含一个对象数组:
{
"theList": [
{
"id": 1,
"name": "Horst"
},
{
"id": 2,
"name": "Fritz"
},
{
"id": 3,
"name": "Walter"
},
{
"id": 4,
"name": "Gerhart"
},
{
"id": 5,
"name": "Harmut"
}
]
}
我想过滤该列表以仅显示 id 值为 2 和 4 的元素,因此预期输出为:
{
"id": 2,
"name": "Fritz"
},
{
"id": 4,
"name": "Gerhart"
}
如何使用 jq 过滤 json?我玩过 select 和地图,但没有任何一个可以工作,例如:
$ jq '.theList[] | select(.id == 2) or select(.id == 4)' array.json
true
来自文档:
jq '.[] | select(.id == "second")'
Input [{"id": "first", "val": 1}, {"id": "second", "val": 2}]
Output {"id": "second", "val": 2}
我想你可以这样做:
jq '.theList[] | select(.id == 2 or .id == 4)' array.json
您可以在 map
内使用 select
。
.theList | map(select(.id == (2, 4)))
或更紧凑:
[ .theList[] | select(.id == (2, 4)) ]
虽然这样写有点低效,因为表达式对于每个被比较的值都是重复的。这样写会更有效率,也可能更易读:
[ .theList[] | select(any(2, 4; . == .id)) ]
这是一个使用 indices 的解决方案:
.theList | [ .[map(.id)|indices(2,4)[]] ]
这里使用select(.id == (2, 4))
通常是低效的(见下文)。
如果你的jq有IN/1
,那么可以用它来实现更高效的解决方案:
.theList[] | select( .id | IN(2,3))
如果你的jq没有IN/1
,那么你可以这样定义:
def IN(s): first(select(s == .)) // false;
效率
查看效率低下的一种方法是使用 debug
。例如,以下表达式导致对 debug
的 10 次调用,而实际上只需要 9 次检查是否相等:
.theList[] | select( (.id == (2,3)) | debug )
["DEBUG:",false]
["DEBUG:",false]
["DEBUG:",true]
{
"id": 2,
"name": "Fritz"
}
["DEBUG:",false]
["DEBUG:",false]
["DEBUG:",true]
{
"id": 3,
"name": "Walter"
}
["DEBUG:",false]
["DEBUG:",false]
["DEBUG:",false]
["DEBUG:",false]
index/1
原则上,使用 index/1
应该是高效的,但截至撰写本文时(2017 年 10 月),其实现虽然速度很快(用 C 编写),但效率低下。
我喜欢使用 jq:
过滤 json 个文件jq . some.json
假设 json 包含一个对象数组:
{
"theList": [
{
"id": 1,
"name": "Horst"
},
{
"id": 2,
"name": "Fritz"
},
{
"id": 3,
"name": "Walter"
},
{
"id": 4,
"name": "Gerhart"
},
{
"id": 5,
"name": "Harmut"
}
]
}
我想过滤该列表以仅显示 id 值为 2 和 4 的元素,因此预期输出为:
{
"id": 2,
"name": "Fritz"
},
{
"id": 4,
"name": "Gerhart"
}
如何使用 jq 过滤 json?我玩过 select 和地图,但没有任何一个可以工作,例如:
$ jq '.theList[] | select(.id == 2) or select(.id == 4)' array.json
true
来自文档:
jq '.[] | select(.id == "second")'
Input
[{"id": "first", "val": 1}, {"id": "second", "val": 2}]
Output
{"id": "second", "val": 2}
我想你可以这样做:
jq '.theList[] | select(.id == 2 or .id == 4)' array.json
您可以在 map
内使用 select
。
.theList | map(select(.id == (2, 4)))
或更紧凑:
[ .theList[] | select(.id == (2, 4)) ]
虽然这样写有点低效,因为表达式对于每个被比较的值都是重复的。这样写会更有效率,也可能更易读:
[ .theList[] | select(any(2, 4; . == .id)) ]
这是一个使用 indices 的解决方案:
.theList | [ .[map(.id)|indices(2,4)[]] ]
这里使用select(.id == (2, 4))
通常是低效的(见下文)。
如果你的jq有IN/1
,那么可以用它来实现更高效的解决方案:
.theList[] | select( .id | IN(2,3))
如果你的jq没有IN/1
,那么你可以这样定义:
def IN(s): first(select(s == .)) // false;
效率
查看效率低下的一种方法是使用 debug
。例如,以下表达式导致对 debug
的 10 次调用,而实际上只需要 9 次检查是否相等:
.theList[] | select( (.id == (2,3)) | debug )
["DEBUG:",false]
["DEBUG:",false]
["DEBUG:",true]
{
"id": 2,
"name": "Fritz"
}
["DEBUG:",false]
["DEBUG:",false]
["DEBUG:",true]
{
"id": 3,
"name": "Walter"
}
["DEBUG:",false]
["DEBUG:",false]
["DEBUG:",false]
["DEBUG:",false]
index/1
原则上,使用 index/1
应该是高效的,但截至撰写本文时(2017 年 10 月),其实现虽然速度很快(用 C 编写),但效率低下。