34
\$\begingroup\$

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
\$\endgroup\$
5
  • 4
    \$\begingroup\$ After discussion in chat I've decided to allow length built-ins, because some languages require them to iterate over an array cleanly. \$\endgroup\$ – Martin Ender Feb 8 '16 at 23:09
  • 4
    \$\begingroup\$ Just for general education: is APL's built-in primitive for exactly this. \$\endgroup\$ – Adám Feb 9 '16 at 16:09
  • \$\begingroup\$ @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? \$\endgroup\$ – Ashwin Gupta Feb 10 '16 at 5:21
  • \$\begingroup\$ @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. \$\endgroup\$ – Martin Ender Feb 10 '16 at 10:39
  • \$\begingroup\$ @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? \$\endgroup\$ – Ashwin Gupta Feb 10 '16 at 22:02

44 Answers 44

1
2
1
\$\begingroup\$

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.

\$\endgroup\$
1
\$\begingroup\$

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.

\$\endgroup\$
1
\$\begingroup\$

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

And it's actually readable. :)

\$\endgroup\$
1
  • 1
    \$\begingroup\$ Welcome to the site! \$\endgroup\$ – James Sep 7 '17 at 17:02
1
\$\begingroup\$

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)
```
\$\endgroup\$
4
  • \$\begingroup\$ 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. \$\endgroup\$ – Wheat Wizard Jul 31 '20 at 2:40
  • \$\begingroup\$ Didn't realize that wasn't allowed, updated to reflect that. \$\endgroup\$ – Benrob0329 Jul 31 '20 at 4:15
  • \$\begingroup\$ You can save one byte by replacing arg[1] with (...) \$\endgroup\$ – val says Reinstate Monica Aug 21 '20 at 16:50
  • \$\begingroup\$ 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? \$\endgroup\$ – Benrob0329 Aug 22 '20 at 4:42
0
\$\begingroup\$

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.

\$\endgroup\$
0
\$\begingroup\$

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;}
\$\endgroup\$
1
  • \$\begingroup\$ Does int m=w=0 work in C# ? \$\endgroup\$ – Cyoce Oct 7 '16 at 0:40
0
\$\begingroup\$

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]
\$\endgroup\$
0
\$\begingroup\$

C++14, 72 70 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;
 }

}
\$\endgroup\$
0
\$\begingroup\$

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]")
\$\endgroup\$
0
\$\begingroup\$

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...

\$\endgroup\$
0
\$\begingroup\$

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!

\$\endgroup\$
0
\$\begingroup\$

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
\$\endgroup\$
0
\$\begingroup\$

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.

\$\endgroup\$
0
\$\begingroup\$

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.

\$\endgroup\$
1
2

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.