独家或(xor)运营商?

时间:2017-09-19 19:12:12

标签: xor jq

jq是否有独占或(AKA xor)运算符?我在文档中找不到它。

(我很难找到我后来发现在jq中工作的文档中的其他主题,并且有记录。我可能最初没有找到它们,因为我使用的搜索条件很差。)

我希望jq从输入中返回所有顶级对象,这些对象的数组属性包含两个特定值中的一个,但不包含两个值。

例如,给定输入:

[
  {"letters": ["a", "c"]},
  {"letters": ["a", "b", "c"]},
  {"letters": ["b", "c"]}
]

我只想要"letters"属性包含"a""b"但不包含两者的对象。

我最终使用了冗长的过滤器:

map(select(.letters//[]|((contains(["a"]) or contains(["b"])) and (contains(["a", "b"])|not))))

给出了正确的输出:

[{"letters":["a","c"]},{"letters":["b","c"]}]

但这是漫长,乏味和维持头痛的问题。有没有更简单的方法来实现这一目标?

此代码的“jq play”代码段:https://jqplay.org/s/mwBhsYud2F

PS:即使没有比我发现的解决方案更好的解决方案,我也很乐意接受有关改进的建设性批评。

3 个答案:

答案 0 :(得分:0)

这个怎么样:如果data.json包含你的样本数据命令

$ jq -Mc '
  def xor($a;$b): $a != $b ;
  map(select(.letters|xor(contains(["a"]);contains(["b"]))))
' data.json

产生

[{"letters":["a","c"]},{"letters":["b","c"]}]

请注意,上面使用的xor在这里工作,但与非布尔参数一起使用是不安全的。更强大的版本是:

def xor($a;$b): ($a|not) != ($b|not) ;

答案 1 :(得分:0)

如果import okhttp3.FormBody; 中没有重复项,这是另一种利用鲜为人知的数组索引方法的方法:

.letters

产生

$ jq -Mc 'map(select(.letters|.[["a"]]+.[["b"]]|length==1))' data.json

这是有效的,因为如果[{"letters":["a","c"]},{"letters":["b","c"]}] 是数组$x,则返回$x[ ["a"] ]"a"的索引。 e.g。

$x

另请参阅jq indices builtin(在implementation中使用它)

与一个更明显的方法相比,如果$ jq -Mnc '["a","c"][["a"]]' [0] $ jq -Mnc '["a","c"][["b"]]' [] $ jq -Mnc '["a","c","a","b"][["a"]]' [0,2] 包含重复项,那么推荐在一般情况下使用这可能太棘手了,那么简单的.letters检查将不起作用。

答案 2 :(得分:0)

xor可以轻松定义:

def xor($a;$b): ($a or $b) and (($a and $b)|not);

contains很棘手(除非你研究过它的细微之处,否则最好不要使用它)。一般来说,最好使用index

.letters | select( xor( index("a"); index("b") ))

为了提高效率,如果你的jq拥有它,那么使用IN会更好:

.letters as $a | select( xor( "a" | IN($a[]); "b" | IN($a[]) ))