为什么 jq 列表构造函数和对象构造函数对生成器的行为不同?

Why jq list contructor and object constructor behaves differently for generators?

我想得到2个列表的笛卡尔积,尝试了以下方法:

echo [[1,2,3],[4,5,6]] | jq '[.[0][],.[1][]]'

我期望得到 [[1,4],[1,5],[1,6],[2,4],[2,5],....],但我真的得到的是 [1,2,3,4,5,6]

但是使用以下 2 个命令,我得到了笛卡尔积输出,

echo [[1,2,3],[4,5,6]] | jq '(.[0][] | tostring) + "," + (.[1][] | tostring)'
echo [[1,2,3],[4,5,6]] | jq '{"x": .[0][], "y": .[1][]}'

我的问题是:为什么逗号的行为与“+”不同?为什么列表构造函数的行为与对象构造函数不同?

因为那是 jq 中的 , operator 的工作原理。当两个过滤器被 , 分隔时,相同的输入将被送入两者,输出值流将按顺序连接起来。在你的例子中,两个过滤器 return 分别在索引 0 和 1 对应的数组元素,结果被收集到一个数组中。

至于Object construction,手册上说的很清楚,

If one of the expressions produces multiple results, multiple dictionaries will be produced.

输入

{"user":"stedolan","titles":["JQ Primer", "More JQ"]}

表达式

{user, title: .titles[]}

产生两个输出,一个对应数组中的每个值 titles

{"user":"stedolan", "title": "JQ Primer"}
{"user":"stedolan", "title": "More JQ"}

所以回到你最初的尝试,

  1. 在第一种情况下,每个表达式 运行 分别在原始输入数组上,结果只是组合在一起成为更大的
  2. 第三种情况属于创建对象的情况,其中一个表达式产生多个结果。由于您的两个表达式都会生成多个结果,因此您的结果字典形成为两个数组的笛卡尔积
  3. 第二种情况与3)几乎相似,但操作发生在字符串类型上,即在生成笛卡尔积之前,每个整数类型都转换为字符串。请注意,这产生的结果 既不是列表也不是字典

执行此操作时,您仍然可以在数组上生成笛卡尔积

.[0][] as $x | .[1][] as $y | [$x,$y]

如果将上面的过滤器放在 [..] 内,则将整个内容放入一个数组中 as

[.[0][] as $x | .[1][] as $y | [$x,$y]]

之所以有效,是因为 Variable binding operator 的语法为 expression as $variable

表达式 exp as $x | ... 表示表达式 exp 的每个值,运行 管道的其余部分具有整个原始输入,并且 $x 设置为价值。因此,作为 foreach 循环的功能。因此,对于我们的示例,对于 $x 中的每个值和 $y 中的每个值,我们形成结果 [$x, $y],这将是最终的笛卡尔积。