# Determine the depth of an array

A simple challenge for your Monday evening (well, or Tuesday morning in the other half of the world...)

You're given as input a nested, potentially ragged array of positive integers:

[1, [[2, 3, [[4], 5], 6, [7, 8]], 9, [10, [[[11]]]], 12, 13], 14]


Your task is to determine its depth, which is the greatest nesting-depth of any integer in the list. In this case, the depth of 11 is 6, which is largest.

You may assume that none of the arrays will be empty.

You may write a program or function, taking input via STDIN (or closest alternative), command-line argument or function argument and outputting the result via STDOUT (or closest alternative), function return value or function (out) parameter.

Input may be taken in any convenient list or string format that supports non-rectangular arrays (with nested arrays of different depths), as long as the actual information isn't preprocessed.

You must not use any built-ins related to the shape of arrays (including built-ins that solve this challenge, that get you the dimensions of a nested array). The only exception to this is getting the length of an array.

Standard rules apply.

### Test Cases

[1]                                                               -> 1
[1, 2, 3]                                                         -> 1
[[1, 2, 3]]                                                       -> 2
[3, [3, [3], 3], 3]                                               -> 3
[[[[1], 2], [3, [4]]]]                                            -> 4
[1, [[3]], [5, 6], [[[[8]]]], 1]                                  -> 5
[1, [[2, 3, [[4], 5], 6, [7, 8]], 9, [10, [[[11]]]], 12, 13], 14] -> 6
[[[[[[[3]]]]]]]                                                   -> 7

• After discussion in chat I've decided to allow length built-ins, because some languages require them to iterate over an array cleanly. – Martin Ender Feb 8 '16 at 23:09
• Just for general education: ≡ is APL's built-in primitive for exactly this. – Adám Feb 9 '16 at 16:09
• @MartinBüttner I've run into a tiny problem. I started doing this in java, unfourtunetly when testing inputs the commas are causing it to split the inputs into multiple command line arguments rather then one. Can I use the escape character \  in the inputs? EDIT: nevermind just tried it like that. That doesn't even work either. Darn can I not use CMD args? – Ashwin Gupta Feb 10 '16 at 5:21
• @AshwinGupta can't you wrap the command line argument in quotes? You can also read input from STDIN or submit a function that takes an actual array object as a parameter. – Martin Ender Feb 10 '16 at 10:39
• @MartinBüttner oh I didn't know that quotes thing I'll try it out. Currently just using Scanner. (System.in). I believe that is a form of STDIN? – Ashwin Gupta Feb 10 '16 at 22:02

# Oracle SQL 11.2, 133 bytes

SELECT MAX(d)FROM(SELECT SUM(DECODE(SUBSTR(:1,LEVEL,1),'[',1,']',-1,0))OVER(ORDER BY LEVEL)d FROM DUAL CONNECT BY LEVEL<=LENGTH(:1));


Un-golfed

SELECT MAX(d)
FROM   (
SELECT SUM(DECODE(SUBSTR(:1,LEVEL,1),'[',1,']',-1,0))OVER(ORDER BY LEVEL) d
FROM   DUAL
CONNECT BY LEVEL<=LENGTH(:1)
);


The CONNECT BY creates one row per character in the input string.

The SUBSTR isolates the character corresponding to the row number.

The DECODE translates each '[' to 1, each ']' to -1 and every other character to 0.

The analytic SUM sums each 1, -1 and 0 from the preceding rows, including the current row;

The MAX sums is the depth.

# Java 8, 95

This is a lambda expression for a ToIntFunction<String>. Input is taken as a String in the OP's examples format.

s->{int d=e=-1;for(String t:s.split("[")){d=++e>d?e:d;e-=t.split("]",-1).length()-1;}return d;}


fairly straightfoward. Split the string using [ as the delimiter. For each of them, increment the counter e and compare it with the counter d, keeping the larger of them in d. Then split the current iteration's string using ] as the delimiter this time and subtract the number of extra splits from e.

# Ruby, 42 characters

f=->a{a==a.flatten(1)?1:f[a.flatten(1)]+1}


Example:

irb(main):001:0> f.call([[[1,2],[2,3]],[[3,4],[5]]])
=> 3


• Welcome to the site! – James Sep 7 '17 at 17:02

# Lua, 101 bytes

d,c=0,0 print(arg[1]:gsub(".",function(s)c=s=='['and c+1 or s==']'and c-1 or c d=c>d and c or d end))


Try it online!

### How it works

-- Passed To Command Line: "[1, [[2, 3, [[4], 5], 6, [7, 8]], 9, [10, [[[11]]]], 12, 13], 14]"

-- Deepest Sub-Array Count, Current Depth
deepest, current = 0, 0

-- We abuse gsub() to iterate over every character in the input string and run a function for it
arg[1]:gsub(".", function(s)
-- The current depth is incremented if s (the current character) is equal to [, OR decremented if s is equal to ], OR left alone
current = (s == '[' and current+1) or (s == ']'and current-1) or current
-- If current is > deepest then deepest = current else deepest = current, we're using boolean logic like a ternary operator
deepest = current > deepest and current or deepest
end)

print(deepest)
$$$$

• How are you taking input? Based on your example it seems like you might be expecting it to be stored in a specific variable? There has been a long standing consensus that this sort of input is only permitted in certain very specific contexts. For a list of ways to take input see this meta thread. – Wheat Wizard Jul 31 '20 at 2:40
• Didn't realize that wasn't allowed, updated to reflect that. – Benrob0329 Jul 31 '20 at 4:15
• You can save one byte by replacing arg[1] with (...) – val says Reinstate Monica Aug 21 '20 at 16:50
• I've heard that ... works in place of the args table, but it doesn't seem to work with 5.3. Is is a 5.4 feature? – Benrob0329 Aug 22 '20 at 4:42

## Perl 6, 70 bytes

Whole program that reads the given examples terminated with newline or EOF from STDIN.

# perl6 % <<< '[1, [[2, 3, [[4], 5], 6, [7, 8]], 9, [10, [[[11]]]], 12, 13], 14]'

my $i;dd [max] lines.comb.map:{$i++when '[';$i--when ']'}  lines takes text line by line from STDIN and returns a list of Str. Calling .comb on a list will convert that into a Str and then split it into graphenes. Any block in Perl 6 is born with one positional argument that ends up in $_. map called with any callable expect it to have one positional argument. What is nice because when ']' is short for when $_ ~~ ']'. The returned list is fed to [max] and reduced to it's biggest value. ## C#, 99 Bytes int f(string s){int m=0,w=0;foreach(char c in s){if(c=='[')w++;if(c==']')w--;if(w>m)m=w;}return m;}  • Does int m=w=0 work in C# ? – Cyoce Oct 7 '16 at 0:40 # Axiom 106 bytes RL(a:Union(List(Any),Any)):INT==(a case List(Any)=>(g:List(Any):=a;r:=1;for i in g repeat r:=r+RL(i);r);0)  ungolf RL(a:Union(List(Any),Any)):INT== a case List(Any)=> g:List(Any):=a r:=1 for i in g repeat r:=r+RL(i) r 0  results (3) -> for i in[[1],[1,2,3], [[1,2,3]], [3,[3,[3],3],3]]repeat output[i, RL(i)] [[1],1] [[1,2,3],1] [[[1,2,3]],2] [[3,[3,[3],3],3],3]  # C++14, 7270 67 bytes -2 bytes for removing the curly brackets at for and -3 bytes for replacing m=l>m?l:m with m+=l>m. As unnamed lambda returning via reference parameter: [](auto&s,int&m){int l=m=0;for(auto c:s)l+=(c==91)-(c==93),m+=l>m;}  s can be std::string or char[] Ungolfed and usage: #include<string> #include<iostream> auto f= [](auto&s,int&m){ int l=m=0; for(auto c:s) l+=(c==91)-(c==93), m+=l>m; } ; int main(){ std::string S[] = { "[1]", "[1, 2, 3]", "[[1, 2, 3]]", "[3, [3, [3], 3], 3]", "[[[[1], 2], [3, [4]]]]", "[1, [[3]], [5, 6], [[[[8]]]], 1]", "[1, [[2, 3, [[4], 5], 6, [7, 8]], 9, [10, [[[11]]]], 12, 13], 14]", "[[[[[[[3]]]]]]]" }; for (auto s:S){ int m; g(s,m); std::cout << m << std::endl; } }  Clojure, 57 bytes (fn[s](apply max(reductions +(map #({$1$ -1}% 0)s))))  Also based on parsing a string: (f "[3, [3, [3], 3], 3]")  R: 53 bytes. d=function(L) ifelse(is.list(L),max(sapply(L,d))+1,0)  Recursive function, it adds one point everytime it finds an inner list. It chooses only the element with the maximum depth... # Scala, 56 bytes val f:Any=>Int={case l:Seq[_]=>l.map(f).max+1 case _=>0}  Make sure the inputs are Seqs and not Lists (I used Seq to save a byte). Try it online! # Pip, 14 bytes {a*0&1+MX:fMa}  Try it online! ### Explanation A recursive function that takes the list as its argument. { } Anonymous function: a The first argument *0 Times 0 (This gives 0 if the argument is a number, or a [possibly nested] list of 0s if the argument is a list) & Logical AND (short-circuiting) (Since 0 is falsey and non-empty lists are truthy in Pip, this halts the recursion and returns 0 if we've reached the inside of the innermost lists; otherwise...) fMa Map this function recursively to each element of a MX: Get the max (: is a no-op to manipulate operator precedence) 1+ Add 1  # Swift - 76 bytes func d(_ a:[Any])->Int{return 1+(a.map{$0 is Int ?0:d(\$0 as![Any])}).max()!}


A recursive function that returns one plus the max of all non ints in the array using map.

# Jelly, 3 bytes

ẎƬL


Try it online!

This is a translation of JohnE's K answer.

Ẏ is the "tighten" command. When applied to a list, it "unwraps" each list in it, essentially reducing the depth by one. Ƭ repeated applies Ẏ to the input until it reaches a fixed point. We then count the number of iterations with L`.