如何使用 jq 过滤 select 不在列表中的项目?

how to use jq to filter select items not in list?

在 jq 中,我可以很容易地select 列表中的项目:

$ echo '["a","b","c","d","e"]' | jq '.[] | select(. == ("a","c"))'

或者如果您更喜欢将其作为数组获取:

$ echo '["a","b","c","d","e"]' | jq 'map(select(. == ("a","c")))'

但是我如何select列表中的所有项目?当然. != ("a","c")不行:

$ echo '["a","b","c","d","e"]' | jq 'map(select(. != ("a","c")))'
[
  "a",
  "b",
  "b",
  "c",
  "d",
  "d",
  "e",
  "e"
]

除了"a""c

,上面的每个项目都给出了两次

同样适用于:

$ echo '["a","b","c","d","e"]' | jq '.[] | select(. != ("a","c"))'
"a"
"b"
"b"
"c"
"d"
"d"
"e"
"e"

如何过滤 匹配项?

我确定这不是最简单的解决方案,但它确实有效:)

$ echo '["a","b","c","d","e"]' | jq '.[] | select(test("[^ac]"))'

编辑: 另一种解决方案 - 这更糟 :)

$ echo '["a","b","c","d","e"]' | jq '.[] | select(. != ("a") and . != ("b"))'

最简单和最可靠的(w.r.t.jq 版本)方法是使用内置 -:

$ echo '["a","b","c","d","e"]' | jq -c '. - ["a","c"]'
["b","d","e"]

如果黑名单很长并且充满了重复项,那么删除它们可能是合适的(例如 unique)。

变化

这个问题也可以用 indexnot 来解决(在 jq 1.4 及更高版本中),例如

["a","c"] as $blacklist
| .[] | select( . as $in | $blacklist | index($in) | not) 

或者,使用从命令行传入的变量(jq --argjson blacklist ...):

.[] | select( . as $in | $blacklist | index($in) | not) 

要保留列表结构,可以使用map( select( ...) )

对于 jq 1.5 或更高版本,您还可以使用 anyall,例如

def except(blacklist):
  map( select( . as $in | blacklist | all(. != $in) ) );

特例:字符串

参见例如