jq: Get dimensions of 2d array

Viewed 280

I'd like to retrieve the dimensions of a 2D array with jq.

test.json:

{
  "data": [
    [1,2,3,4],
    [5,6,7,8]
  ]
}

I can get the major dimension:

$ jq < test.json '.data | length'
2

I can get the minor dimension:

$ jq < test.json '.data[0] | length'
4

I would like to get both at once, ie: (does not work, expected output)

$ jq < test.json '.data | [length, .[0] ???? ]'
[
  2,
  4
]

Is there any way to produce this expected output with jq?

2 Answers

Here's a general solution for a strictly regular, n-dimensional array:

.data | [recurse( .[0]? | select(type=="array")) |  length]

For more about the concept of strict regularity, see below.

As a function

With

def rho: [recurse( .[0]? | select(type=="array")) |  length];

[ [[1,1],[2,2]], [[1,1],[2,2]], [[1,1],[2,2]]] | rho

would yield: [3,2,2]

Strict regularity

For present purposes, let's say a "matrix" is strictly regular if none of its entries is an array, and that an n-dimensional JSON array is strictly regular if and only if the corresponding n-dimensional matrix is strictly regular.

To check that a JSON array is strictly regular in this sense, we can define is_strictly_regular (using the above definition of rho) as follows:

# Check whether the input has precisely the specified
# dimensions, and no additional arrays.
# It is assumed that $dimensions is an array of non-negative integers.
# If $dimensions is [], then return type!="array".
def strictcheck($dimensions):
  if type == "array"
  then ($dimensions|length) > 0
       and length == $dimensions[0]
       and all(.[]; strictcheck($dimensions[1:]))
  else $dimensions == []
  end;

def is_strictly_regular:
  rho as $d
  | strictcheck($d);

Pipe each separate dimension into length:

$ echo '{
  "data": [
    [1,2,3,4],
    [5,6,7,8]
  ]
}' | jq '.data | [length, (.[0] | length)]'
[
  2,
  4
]

The filter could also be written as

.data | [., .[0]] | map(length)
Related