[英]Using jq to remove items from an array based on values elsewhere in the input
[英]jq: Remove items from array that match a condition based on other items in the same array
我需要一些有点复杂的jq查询的帮助。
特定
[{
"type": "ITEM_PURCHASED",
"timestamp": 1710829,
"participantId": 2,
"itemId": 3089
},
{
"type": "ITEM_PURCHASED",
"timestamp": 1711620,
"participantId": 7,
"itemId": 2055
},
{
"type": "ITEM_PURCHASED",
"timestamp": 1711621,
"participantId": 7,
"itemId": 1058
},
{
"type": "ITEM_PURCHASED",
"timestamp": 1714435,
"participantId": 9,
"itemId": 1037
},
{
"type": "ITEM_UNDO",
"timestamp": 1716107,
"participantId": 7,
"afterId": 0,
"beforeId": 2055
},
{
"type": "ITEM_UNDO",
"timestamp": 1716272,
"participantId": 7,
"afterId": 0,
"beforeId": 1058
},
{
"type": "ITEM_PURCHASED",
"timestamp": 1718091,
"participantId": 7,
"itemId": 1026
}]
期望的输出:
[{
"type": "ITEM_PURCHASED",
"timestamp": 1710829,
"participantId": 2,
"itemId": 3089
},
{
"type": "ITEM_PURCHASED",
"timestamp": 1714435,
"participantId": 9,
"itemId": 1037
},
{
"type": "ITEM_PURCHASED",
"timestamp": 1718091,
"participantId": 7,
"itemId": 1026
}]
我想过滤这个数组,并删除所有“撤消”的购买项目。 可以通过在具有更高时间戳,匹配的participantId和beforeId == itemId之后添加ITEM_UNDONE对象来撤消PURCHASE_ITEM对象。
我尝试了以下方法:
第2步给了我麻烦。 到目前为止我有以下代码不起作用:
jq '
map(select(.type=="ITEM_UNDO")) as $undos |
[
{
undo: $undos[],
before_purchases: map( select(.type=="ITEM_PURCHASED"
and .itemId == $undos[].beforeId
and .participantId == $undos[].participantId
)
)
}
] as $undo_with_purchased | $undo_with_purchased
'
我知道为什么它不起作用,因为在线
and .itemId == $undos[].beforeId
and .participantId == $undos[].participantId
$ undos独立扩展两次,而不是每次比较使用相同的实例,然后是第三次
undo: $undos[],
我似乎无法找到一种强制方法来强制jq仅迭代$ undos一次并使用相同的实例进行所有比较。 一般来说,我在同时迭代多个阵列时遇到问题,执行操作。 这在任何程序语言中都没有用,但是在jq中做这种事情的最佳方法是什么?
谢谢你的任何建议!
首先,让我们定义一个过滤器,它将告诉数组中的一个项是否已被后续(在数组和时间中)项“撤消”。 这很简单,使用any/2
:
# input: the entire array
# output: true iff item n is "undone" by a subsequent item
def undone($n):
. as $in
| length as $length
| .[$n] as $nth
| if $nth.type != "ITEM_PURCHASED" then false
else any( range($n+1; $length) | $in[.];
.type == "ITEM_UNDO"
and .participantId == $nth.participantId
and .beforeId== $nth.itemId
and .timestamp > $nth.timestamp)
end;
现在查询非常简单:
[ range(0;length) as $i
| select( (.[$i].type == "ITEM_PURCHASED") and (undone($i) | not) )
| .[$i] ]
调用:jq -f program.jq data.json
输出:包含三个项目的数组。
人们可以写:
range($n+1; $length) | $in[.]
更紧凑,也许更具惯用性,如:
$in[range($n+1; $length)]
事实上, $in
和$length
都可以完全免除,所以有问题的片段会变得简单:
.[range($n+1; length)]
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.