jq中的向量数学算术运算
Vector math arithmetic operations in jq
我想对存储数字的 json 数组执行向量数学运算。总之如何使用jq实现一对一的算术运算呢?
我尝试使用 'map' 过滤器,但无法达到我的预期。
jq 'map(one-to-one)' <<< "{\"a\":[1,2], \"b\":[3,4]}"
或
jq 'map(one-to-one)' <<< "[[1,2],[3,4]]"
应该生产
[3,8]
jq '. | transpose | map(reduce .[] as $item (1; . * $item))' <<< "[[1,2],[3,4]]"
Transpose 为我们提供了需要相乘的元素:[[1, 3], [2, 4]]
。然后我们可以使用 reduce.
将每个子数组映射到它的乘积。
对象版本略有不同,因为我们需要从属性中获取这些值:
jq '[.[]] | transpose | map(reduce .[] as $item (1; . * $item))' <<< "{\"a\":[1,2], \"b\":[3,4]}"
对于这类问题,定义一个泛型函数是有意义的:
# Input is assumed to be an array of two numeric arrays of the same length
def pairwise: transpose | map(.[0] * .[1]);
我们现在可以通过多种方式轻松使用它:
[[1,2],[3,4]] | pairwise
{"a":[1,2], "b":[3,4]} | [.a,.b] | pairwise
{"a":[1,2], "b":[3,4]} | [.[]] | pairwise
每种情况下的结果当然是[3,8]
。
效率
对于非常大的输入,可能值得避免 transpose
:
def pairwise:
.[0] as $x | .[1] as $y
| reduce range(0; $x|length) as $i ([]; . + [$x[$i] * $y[$i]]);
通常对于向量,人们对内积感兴趣,为了提高效率,最好直接定义内积,例如如下:
def inner($a; $b):
reduce range(0;$a|length) as $i (0; . + $a[$i]*$b[$i]);
我想对存储数字的 json 数组执行向量数学运算。总之如何使用jq实现一对一的算术运算呢?
我尝试使用 'map' 过滤器,但无法达到我的预期。
jq 'map(one-to-one)' <<< "{\"a\":[1,2], \"b\":[3,4]}"
或
jq 'map(one-to-one)' <<< "[[1,2],[3,4]]"
应该生产
[3,8]
jq '. | transpose | map(reduce .[] as $item (1; . * $item))' <<< "[[1,2],[3,4]]"
Transpose 为我们提供了需要相乘的元素:[[1, 3], [2, 4]]
。然后我们可以使用 reduce.
对象版本略有不同,因为我们需要从属性中获取这些值:
jq '[.[]] | transpose | map(reduce .[] as $item (1; . * $item))' <<< "{\"a\":[1,2], \"b\":[3,4]}"
对于这类问题,定义一个泛型函数是有意义的:
# Input is assumed to be an array of two numeric arrays of the same length
def pairwise: transpose | map(.[0] * .[1]);
我们现在可以通过多种方式轻松使用它:
[[1,2],[3,4]] | pairwise
{"a":[1,2], "b":[3,4]} | [.a,.b] | pairwise
{"a":[1,2], "b":[3,4]} | [.[]] | pairwise
每种情况下的结果当然是[3,8]
。
效率
对于非常大的输入,可能值得避免 transpose
:
def pairwise:
.[0] as $x | .[1] as $y
| reduce range(0; $x|length) as $i ([]; . + [$x[$i] * $y[$i]]);
通常对于向量,人们对内积感兴趣,为了提高效率,最好直接定义内积,例如如下:
def inner($a; $b):
reduce range(0;$a|length) as $i (0; . + $a[$i]*$b[$i]);