Search code examples
jsonmathvectorjqvector-multiplication

Vector math arithmetic operations in jq


I'd like to perform vector math operations on a json array that stores numbers. In short how can we achieve one to one arithmetic operations by using jq?

I tried something with 'map' filter however could not achieved what I expect.

jq 'map(one-to-one)' <<< "{\"a\":[1,2], \"b\":[3,4]}"

or

jq 'map(one-to-one)' <<< "[[1,2],[3,4]]"

should produce

[3,8]

Solution

  • For this type of problem, it makes sense to define a generic function:

    # Input is assumed to be an array of two numeric arrays of the same length
    def pairwise: transpose | map(.[0] * .[1]);
    

    We can now easily use this in a variety of ways:

    [[1,2],[3,4]] | pairwise
    
    {"a":[1,2], "b":[3,4]} | [.a,.b] | pairwise
    
    {"a":[1,2], "b":[3,4]} | [.[]] | pairwise
    

    The result in each of these cases is of course [3,8].

    Efficiency

    For very large inputs, it might be worthwhile avoiding transpose:

    def pairwise:
       .[0] as $x | .[1] as $y 
       | reduce range(0; $x|length) as $i ([]; . + [$x[$i] * $y[$i]]);
    

    Typically with vectors one is interested in the inner product, which for efficiency would best be defined directly, e.g. as follows:

    def inner($a; $b):
      reduce range(0;$a|length) as $i (0; . + $a[$i]*$b[$i]);