现在,这有点类似于jq: select only an array which contains element A but not element B,但它不知何故对我有用(这可能是我的错)......; - )
所以我们拥有的是:
[ {
"employeeType": "student",
"cn": "dc8aff1",
"uid": "dc8aff1",
"ou": [
"4210910",
"4210910 #Abg",
"4210910 Abgang",
"4240115",
"4240115 5",
"4240115 5\/5"
]
},
{
"employeeType": "student",
"cn": "160f656",
"uid": "160f656",
"ou": [
"4210910",
"4210910 3",
"4210910 3a"
] } ]
我想选择不包含特定字符串的所有元素,例如" 4210910 3a"或者 - 哪个更好 - 你不包含给定字符串列表的任何成员。
答案 0 :(得分:2)
当涉及到可能更改输入时,您应该将其作为过滤器的参数,而不是将其硬编码。另外,使用contains
可能对您不起作用。它以递归方式运行过滤器,因此即使子字符串匹配也可能不是首选。
例如:
["10", "20", "30", "40", "50"] | contains(["0"])
是true
我会这样写:
$ jq --argjson ex '["4210910 3a"]' 'map(select(all(.ou[]; $ex[]!=.)))' input.json
答案 1 :(得分:1)
这个响应解决了.ou是一个数组的问题,并给出了另一个禁用字符串数组。
为清楚起见,让我们定义一个过滤器intersectq(a;b)
,如果数组有一个共同的元素,它将返回true:
def intersectq(a;b):
any(a[]; . as $x | any( b[]; . == $x) );
这实际上是一个循环内循环,但由于any/2
的语义,一旦找到匹配,计算就会停止。(*)
假设$ ex是异常列表,那么我们可以用来解决问题的过滤器是:
map(select(intersectq(.ou; $ex) | not))
例如,我们可以按照Jeff建议的方式使用调用:
$ jq --argjson ex '["4210910 3a"]' -f myfilter.jq input.json
现在你可能会问:为什么要使用any-within-any-double循环而不是。[] - 所有双循环?答案是效率,可以使用debug
:
$ jq -n '[1,2,3] as $a | [1,1] as $b | all( $a[]; ($b[] | debug) != .)'
["DEBUG:",1]
["DEBUG:",1]
false
$ jq -n '[1,2,3] as $a | [1,1] as $b | all( $a[]; . as $x | all( $b[]; debug | $x != .))'
["DEBUG:",1]
false
(*)脚注
当然,这里定义的intersectq/2
仍然是O(m * n),因此效率低,但这篇文章的要点是强调。[] - 所有双循环的缺点。
答案 2 :(得分:0)
此解决方案使用 foreach 和包含检查输入的每个元素的.ou
成员。
["4210910 3a"] as $list # adjust as necessary
| .[]
| foreach $list[] as $e (
.; .; if .ou | contains([$e]) then . else empty end
)
编辑:我现在意识到foreach E as $X (.; .; R)
形式的过滤器几乎总是被重写为E as $X | R
所以上面的内容实际上就是
["4210910 3a"] as $list
| .[]
| $list[] as $e
| if .ou | contains([$e]) then . else empty end