Arrays 如何使用jq获得两个JSON数组的交集

Arrays 如何使用jq获得两个JSON数组的交集,arrays,json,intersection,jq,Arrays,Json,Intersection,Jq,给定数组X和Y(最好两者都作为输入,否则,一个作为输入,另一个硬编码),如何使用jq输出包含这两个元素共有的所有元素的数组?e、 g.f的值是多少 echo '[1,2,3,4]' | jq 'f([2,4,6,8,10])' 将输出 [2,4] ? 我尝试了以下方法: map(select(in([2,4,6,8,10]))) --> outputs [1,2,3,4] select(map(in([2,4,6,8,10]))) --> outputs [1,2,3,4,5

给定数组X和Y(最好两者都作为输入,否则,一个作为输入,另一个硬编码),如何使用jq输出包含这两个元素共有的所有元素的数组?e、 g.f的值是多少

echo '[1,2,3,4]' | jq 'f([2,4,6,8,10])'
将输出

[2,4]
?

我尝试了以下方法:

map(select(in([2,4,6,8,10])))  --> outputs [1,2,3,4]
select(map(in([2,4,6,8,10])))  --> outputs [1,2,3,4,5]
一个简单且相当快速(但有点幼稚)的过滤器基本上可以实现您想要的功能,其定义如下:

   # x and y are arrays
   def intersection(x;y):
     ( (x|unique) + (y|unique) | sort) as $sorted
     | reduce range(1; $sorted|length) as $i
         ([]; if $sorted[$i] == $sorted[$i-1] then . + [$sorted[$i]] else . end) ;
如果在STDIN上提供x作为输入,而以其他方式提供y(例如
defy:…
),则可以将其用作:
交叉点(;y)

提供两个不同数组作为输入的其他方法包括:

  • 使用
    --slurp
    选项
  • 使用
    --arg a v
    (或
    --argjson a v
    ,如果jq中提供)
这里有一个更简单但速度较慢的def,但在实践中速度相当快:

    def i(x;y):
       if (y|length) == 0 then []
       else (x|unique) as $x
       | $x - ($x - y)
       end ;
这里有一个独立的过滤器,用于查找任意多个数组的交集:

# Input: an array of arrays
def intersection:
  def i(y): ((unique + (y|unique)) | sort) as $sorted
  | reduce range(1; $sorted|length) as $i
       ([]; if $sorted[$i] == $sorted[$i-1] then . + [$sorted[$i]] else . end) ;
  reduce .[1:][] as $a (.[0]; i($a)) ;
示例:

[ [1,2,4], [2,4,5], [4,5,6]] #=> [4]
[[]]                         #=> []
[]                           #=> null

当然,如果已知
x
y
是排序和/或唯一的,则可能有更有效的解决方案。具体请参见这里的解决方案,它使用foreach计算数组中元素的出现次数

[
  foreach ($X[], $Y[]) as $r (
    {}
  ; .[$r|tostring] += 1
  ; if .[$r|tostring] == 2 then $r else empty end
  )
]
如果此筛选器位于
filter.jq
中,则

jq -M -n -c --argjson X '[1,2,3,4]' --argjson Y '[2,4,6,8,10]' -f filter.jq
将产生

[2,4]
它假定初始数组中没有重复项。如果情况并非如此,则很容易使用独特的进行补偿。例如

[
  foreach (($X|unique)[], ($Y|unique)[]) as $r (
    {}
  ; .[$r|tostring] += 1
  ; if .[$r|tostring] == 2 then $r else empty end
  )
]
简单解释 所有这些答案的复杂性模糊了对这一原则的理解。这很不幸,因为原则很简单:

  • array1减去array2返回:
  • 所有留在阵列中的东西1
  • 移除阵列2中的所有内容后
  • (并丢弃阵列2的其余部分)
简单演示
#从array1中减去array2,留下余数
$jq—空输入“[1,2,3,4]-[2,4,6,8]”
[
1.
3.
]
#从原始值中减去余数
$jq—空输入“[1,2,3,4]-[1,3]”
[
2.
4.
]
#把它们放在一起
$jq—空输入“[1,2,3,4]-([1,2,3,4]-[2,4,6,8])”
[
2.
4.
]
comm
Demo
def通信:
([0]-([0]-[1])作为$d|
[[0]-$d,[1]-$d,$d]
;
有了这种理解,我就能够模仿

在没有选项的情况下,生成三列输出。第一栏 包含文件1唯一的行,第二列包含唯一的行 第三列包含两个文件共有的行

$echo'def comm:([0]-([0]-[1])作为$d |[0]-$d,[1]-$d,$d];”>通信jq
$echo'{“a”:101,“b”:102,“c”:103,“d”:104}>1.json
$echo'{“b”:202,“d”:204,“f”:206,“h”:208}>2.json
$jq--slurp'.'1.json 2.json
[
{
“a”:101,
“b”:102,
“c”:103,
“d”:104
},
{
“b”:202,
“d”:204,
“f”:206,
“h”:208
}
]
$jq--slurp'[.]| keys | sort]'1.json 2.json
[
[
“a”,
“b”,
“c”,
“d”
],
[
“b”,
“d”,
“f”,
“h”
]
]
$jq——slurp'包括“comm”;[.]|键|排序]| comm'1.json 2.json
[
[
“a”,
“c”
],
[
“f”,
“h”
],
[
“b”,
“d”
]
]
$jq——slurp'包括“comm”;[.]|键|排序]|命令[2]'1.json 2.json
[
“b”,
“d”
]

对于jq来说似乎异常冗长,但它确实有效,这对于我尝试过的任何其他解决方案来说都是不可能的。谢谢。如何在.jq文件中使用此函数?我不明白为什么这不起作用:
jq-f plugin-group.jq plugins.json
交叉点
,这里定义为arity 0。也许你的意思是:
.intersection=([.servers[].installed]| intersection)
请在回答中添加更多细节。为什么这样做有效?你解决的问题是什么?这使得OP和未来的每个人都更容易理解他们的问题。此解决方案要求将两个数组分别传递给
jq
jq
在输出中包括第二个数组的每个元素(如果它存在于第一个数组中)。我猜
jq
会在第二个数组中线性搜索第一个数组的每个元素。在某些情况下,这些都是很好的解决方案,但如果存在“冲突”,则会给出错误的答案,因为(例如)数字1和字符串“1”都映射到后一个值。
$ echo '[1,2,3,4] [2,4,6,8,10]' | jq --slurp '[.[0][] as $x | .[1][] | select($x == .)]'
[
  2,
  4
]