7
$\begingroup$

ArrayDepth[expr] gives the depth to which expr is a full array, with all the parts at a particular level being lists of the same length, or is a SparseArray object.

OK, so ArrayDepth of a symbol (i.e. a scalar quantity) gives 0:

In[1]:=  ArrayDepth[f]
Out[1]:= 0

But:

In[2]:=  ArrayDepth[f[x]]
Out[2]:= 1

Why? f[x] is still not a List!

When I have a List of vector components, then it makes no difference if these components are functions or just symbols:

In[3]:= ArrayDepth[{f, g, h}]
Out[3]:= 1

In[4]:= ArrayDepth[{f[x], g[x], h[x]}]
Out[4]:= 1

Is there a function in Mathematica that returns the true "nestedness" of the List, i.e. the number of indices needed to access elements of the List, without paying attention to square brackets? (I assume regular nested lists, where all levels have the same length). So it should give 0 for any non-List, 1 for vectors, 2 for regular matrices, etc.

$\endgroup$
  • $\begingroup$ You missed the "Generalizations and Extensions" part of the docs for ArrayDepth[], I take it. Anyway... "I assume regular nested lists, where all levels have the same length" - so, something that passes ArrayQ[]. $\endgroup$ – J. M. will be back soon Nov 15 '17 at 10:07
  • 1
    $\begingroup$ Very related: mathematica.stackexchange.com/q/141777/26956 $\endgroup$ – LLlAMnYP Nov 15 '17 at 10:28
  • $\begingroup$ @J.M. so something that passes ArrayQ Unclear, if you ask me. So a "regular" matrix which has some of its elements as lists has an ArrayDepth of 0? $\endgroup$ – LLlAMnYP Nov 15 '17 at 10:34
  • $\begingroup$ @LLlAMnYP, I was hoping the OP would look at the first point of the docs for ArrayQ[]: "ArrayQ[expr] gives True if expr is a full array or a SparseArray object, and gives False otherwise." $\endgroup$ – J. M. will be back soon Nov 15 '17 at 10:37
  • 2
    $\begingroup$ I think an answer using the option AllowedHeads (currently undocumented, but probably not going away) would be useful. $\endgroup$ – Carl Woll Dec 7 '17 at 18:12
7
$\begingroup$

Something relatively simple:

myArrayDepth[arr_] := If[ArrayQ[arr], ArrayDepth[arr], 0]

Test:

ArrayDepth[f[f[a, b], f[c, d]]]
   2

myArrayDepth[f[f[a, b], f[c, d]]]
   0

Alternatively, use TensorRank[]:

TensorRank[{{1, 3}, {2, 4}}]
   2

TensorRank[SparseArray[{1, 1} -> 1, {2, 2}]]
   2

which remains unevaluated if given something that isn't a List[] or a SparseArray[]:

TensorRank[f[f[a, b], f[c, d]]]
   TensorRank[f[f[a, b], f[c, d]]]

and throws a warning if not passed a rectangular array:

TensorRank[{{1, 2}, {3}}]
>> TensorRank::rect: Nonrectangular array encountered.
   1
$\endgroup$
  • $\begingroup$ Yeah, I've implemented code like that, but I was actually wondering about the logic behind the built-in ArrayDepth. What is the reason for it to consider square brackets as indicator of dimension if no curly braces are given? $\endgroup$ – That Guy Nov 15 '17 at 10:37
  • 3
    $\begingroup$ @ThatGuy The reason is that curly braces are shorthand for List[]. List[List[1, 2], List[3, 4]] is the same as {{1,2},{3,4}} and has an array depth of 2. If we replace List with f to get f[f[1,2],f[3,4]] the depth won't change. $\endgroup$ – LLlAMnYP Nov 15 '17 at 10:40
  • 2
    $\begingroup$ @ThatGuy square brackets are irrelevant, that's just the way syntax is done in Mathematica. What's relevant is what is immediately before the square brackets, in this case List or f and all instances of that must be the same for it to be a full array (so f[f[1,2]] is fine (depth 2), but f[g[1,2]] isn't (depth 1). $\endgroup$ – LLlAMnYP Nov 15 '17 at 10:42
  • $\begingroup$ TensorRank is a nice choice. At least its output is always independent of whether I use square brackets inside. $\endgroup$ – ThisGuy Nov 15 '17 at 13:32
7
$\begingroup$

There is an undocumented option AllowedHeads that can be used for this purpose (so the usual warnings about undocumented features applies here):

ArrayDepth[f[f[a,b], f[c,d]], AllowedHeads->{List}]
ArrayDepth[f[f[a,b], f[c,d]], AllowedHeads->{f}]

0

2

You can use SetOptions in an init.m file to change the default:

SetOptions[ArrayDepth, AllowedHeads->{List}];
ArrayDepth[{{a,b}, {c,d}}]
ArrayDepth[f[f[a,b], f[c,d]]]

2

0

Note that you can also mix and match heads using this option, but note that the heads have to be the same at any particular level:

ArrayDepth[f[{a,b}, {c,d}], AllowedHeads->{List, f}]
ArrayDepth[f[{a,b}, f[c,d]], AllowedHeads->{List, f}]

2

1

$\endgroup$
2
$\begingroup$

In line with my answer from the linked question:

myArrayDepth[arr_] := ArrayDepth[{arr}] - 1

Just like J.M.'s answer:

ArrayDepth[f[f[a, b], f[c, d]]]
myArrayDepth[f[f[a, b], f[c, d]]]
2
0
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.