jq筛选器:如果项目不在列表中,则确定

时间:2019-11-15 11:26:21

标签: arrays json jq indexof

(这里是jq新手,很抱歉,如果这个问题的答案很明显:))

我想根据列表中的值是否 not 来过滤json。

这是一个具体示例:

输入

[ 
    {
        "n": "A",
        "a": 659533330984,
        "vals": {
            "n2": "B",
            "b": 5193941030
        }
     },
    {
        "n": "A",
        "a": 659533330984,
        "vals": {
            "n2": "C",
            "b": 4872891707
        }
    },
    {
        "n": "B",
        "a": 659533330984,
        "vals": {
            "n2": "C",
            "b": 4872891707
        }
    }
]

过滤器

[.n, .vals.n2]不在(["A", "B"], ["B", "C"])

因此,在jq中,我尝试了以下命令(也基于this related question

jq '[ .[] | select([.n, .vals.n2] as $i | (["A", "B"], ["B", "C"]) | index($i) | not )]'

jq '[ .[] | select([.n, .vals.n2] != (["A", "B"], ["B", "C"]))]'

但是,两个命令都提供输出

[
  {
    "n": "A",
    "a": 659533330984,
    "vals": {
      "n2": "B",
      "b": 5193941030
    }
  },
  {
    "n": "A",
    "a": 659533330984,
    "vals": {
      "n2": "C",
      "b": 4872891707
    }
  },
  {
    "n": "A",
    "a": 659533330984,
    "vals": {
      "n2": "C",
      "b": 4872891707
    }
  },
  {
    "n": "B",
    "a": 659533330984,
    "vals": {
      "n2": "C",
      "b": 4872891707
    }
  }
]

这将是理想的输出-没有重复且所有“列入黑名单”的值都具有逻辑AND:

[
  {
    "n": "A",
    "a": 659533330984,
    "vals": {
      "n2": "C",
      "b": 4872891707
    }
  }
]

第二个命令不起作用是有道理的,因为如果我理解正确的话,逗号运算符基本上意味着jq对列出的每个元素都一次评估表达式-因此重复。但是,仅通过unique进行管道传输无济于事,因为输出不应包含过滤器对的 any

我目前唯一的另一个想法是通过“选择...”到“黑名单”中的每个项目通过选择进行选择。但是,我想将黑名单作为输入读取-我可以动态创建命令,但是我想知道是否有更漂亮的解决方案?好像必须要...

我很高兴听到您对如何最好地做到这一点的意见。

我正在使用jq版本jq-1.5-1-a5b5cbe。

2 个答案:

答案 0 :(得分:1)

表达式:

([.n, .vals.n2]) not in (["A", "B"], ["B", "C"])

将等同于:

([.n, .vals.n2]) != ["A", "B"] and ([.n, .vals.n2]) != ["B", "C"]

在这里拥有它:

select([.n, .vals.n2] != (["A", "B"], ["B", "C"]))

与逗号实际上使它成为or不太一样。

您需要做更多类似的事情:

select([.n, .vals.n2] as $v | $v != ["A", "B"] and $v != ["B", "C"])

select([.n, .vals.n2] as $v | all(["A", "B"], ["B", "C"]; $v != .))

此外,如果您想坚持第一种方法,则必须将值放入数组中,而不仅仅是用逗号隔开。

select([.n, .vals.n2] as $i | [["A", "B"], ["B", "C"]] | index($i) | not)

答案 1 :(得分:1)

使用index查找数组的索引(例如$ x)时,您必须编写:

index([$x])

(这与index旨在在JSON字符串和数组上以统一方式工作的事实有关。)

有效的解决方案

[["A", "B"], ["B", "C"]] as $blacklist
| map( [.n, .vals.n2] as $i
       | select( $blacklist | index([$i]) | not) )

来自jq FAQ

  

?:给定一个数组A,其中包含项X,如何找到A中X的最小索引?为什么[1] | index(1)返回null而不是0?为什么[1,2] | index([1,2])返回0而不是null?

     

A:查找数组中X的最小索引的最简单的统一方法是查询[X]而不是X本身,即:index([X])。

     

通过对比,过滤器索引([1,2])尝试查找[1,2]作为输入数组中连续项目的子序列。这是为了使t |的行为具有一致性。索引,其中s和t是字符串。

     

如果X不是数组,则index([X])可以缩写为index(X)。