Visualize an Array

26

4

Given an array of any depth, draw its contents with borders of +-| around each subarray. Those are the ASCII characters for plus, minus, and vertical pipe.

For example, if the array is [1, 2, 3], draw

+-----+
|1 2 3|
+-----+

For a nested array such as [[1, 2, 3], [4, 5], [6, 7, 8]], draw

+-----------------+
|+-----+---+-----+|
||1 2 3|4 5|6 7 8||
|+-----+---+-----+|
+-----------------+

For a ragged array such as [[[1, 2, 3], [4, 5]], [6, 7, 8]], draw

+-------------------+
|+-----------+-----+|
||+-----+---+|6 7 8||
|||1 2 3|4 5||     ||
||+-----+---+|     ||
|+-----------+-----+|
+-------------------+

Notice that there is more space after drawing [6, 7, 8]. You may either draw the contents on the top-most, center, or bottom-most line, but whichever you choose, you must remain consistent.

This challenge was inspired by the box verb < from J.

Rules

  • This is so the shortest code wins.
  • Builtins that solve this are not allowed.
  • The input array will contain only nonnegative integer values or arrays. Each array will be homogenous, meaning that its elements will either by only arrays or only integers, but never a mix of both.
  • Each subarray may be nested to any depth.
  • The output may either by as a string or as an array of strings where each string is a line of output.

Test Cases

[]
++
||
++

[[], []]
+---+
|+++|
|||||
|+++|
+---+

[[], [1], [], [2], [], [3], []]
+-----------+
|++-++-++-++|
|||1||2||3|||
|++-++-++-++|
+-----------+

[[[[[0]]]]]
+---------+
|+-------+|
||+-----+||
|||+---+|||
||||+-+||||
|||||0|||||
||||+-+||||
|||+---+|||
||+-----+||
|+-------+|
+---------+

[[[[[4, 3, 2, 1]]]], [[[3, 2, 1]]], [[2, 1]], [1]]
+---------------------------------+
|+-------------+---------+-----+-+|
||+-----------+|+-------+|+---+|1||
|||+---------+|||+-----+|||2 1|| ||
||||+-------+|||||3 2 1|||+---+| ||
|||||4 3 2 1|||||+-----+||     | ||
||||+-------+|||+-------+|     | ||
|||+---------+||         |     | ||
||+-----------+|         |     | ||
|+-------------+---------+-----+-+|
+---------------------------------+

miles

Posted 2016-10-22T19:32:01.890

Reputation: 15 654

If my language has no nested arrays, can I disregard the definition of the data type? – ThreeFx – 2016-10-22T19:40:39.403

1@ThreeFx You could also take the input as a string representing the nested array – miles – 2016-10-22T19:44:27.813

That is REALLY inefficient (in Haskell). I'd have to parse numbers manually and so on. In that case it would be shorter to define and use the datatype. – ThreeFx – 2016-10-22T19:45:33.427

@ThreeFx Or you could pad the array with sentinel values such as -1 since I also limited the integers to be non-negative. Then would just have to clean the output for those invalid values. – miles – 2016-10-22T19:47:31.230

Sorry about deleting the post I made, I need to fix it up because it wasn't working for one of the test cases. – Gabriel Benamy – 2016-10-22T22:45:49.157

So I guess J's builtin box type representation is disallowed? – Conor O'Brien – 2016-10-22T22:53:10.303

@ConorO'Brien Yes, assuming the default is ascii representation, it completely trivializes the challenge so I had to ban builtins. Also, the sample cases were created in J – miles – 2016-10-22T22:55:46.840

@miles yeah, I figured they were :) – Conor O'Brien – 2016-10-22T23:31:04.537

Extending the bottom border of each inner box downward as much as possible so that the boxes are symmetric across horizontal axis through middle is not valid, I assume? Or would you allow it? I can show you an example if you want, but not now because on phone. – Mitch Schwartz – 2016-10-31T22:16:37.767

Would input format like (1 2 3) instead of [1, 2, 3] be acceptable? – Mitch Schwartz – 2016-10-31T23:49:50.077

Example of extending the boxes downward: http://chat.stackexchange.com/transcript/message/33239514#33239514

– Mitch Schwartz – 2016-11-01T00:46:41.960

1@MitchSchwartz Sure, take the input in a nested tuple or whatever format is native to your language. Your output is fine as long as you remain consistent. Integers can be drawn at the top, center, or bottom, and the boxes can be at the top, center, bottom, or stretched to fill out their space like in your example. – miles – 2016-11-01T02:54:50.727

no test cases with multi-digit integers? – Sparr – 2016-11-01T10:46:30.290

May I have a checkmark? – Adám – 2016-11-01T23:59:54.967

@Adám If you have time, could you add an explanation to your answer. – miles – 2016-11-03T00:48:28.370

@miles Good enough? – Adám – 2016-11-03T08:58:33.533

@Adám That's great, thanks – miles – 2016-11-03T09:02:23.893

Answers

4

Dyalog APL, 56 bytes

Thanks to ngn for helping removing about a third of the bytes.

{⍵≡∊⍵:⍉⍪⍉⍕⍵⋄(⊢,⊣/)⊃,/(1⊖('++','|'⍴⍨≢),'-'⍪⍣2↑)¨↓↑↓¨∇¨⍵}⊂

TryAPL

Define the function, then run each test case and compare to the built-in ]Display utility.
[1, 2, 3]
[[1, 2, 3], [4, 5], [6, 7, 8]]
[[[1, 2, 3], [4, 5]], [6, 7, 8]]
[]
[[], []]
[[], [1], [], [2], [], [3], []]
[[[[[0]]]]]
[[[[[4, 3, 2, 1]]]], [[[3, 2, 1]]], [[2, 1]], [1]]

Explanation

Overall, this is an anonymous function {...} atop an enclose . The latter just adds another level of nesting prompting the former to add an outer frame.

The anonymous function with white-space ( is the statement separator):

{
    ⍵ ≡ ∊⍵: ⍉ ⍪ ⍉ ⍕ ⍵
    (⊢ , ⊣/) ⊃ ,/ (1 ⊖ ('++' , '|' ⍴⍨ ≢) , '-' ⍪⍣2 ↑)¨ ↓ ↑ ↓¨ ∇¨ ⍵
}

Here it is again, but with separated utility functions:

CloseBox ← ⊢ , ⊣/
CreateVertical ← '++' , '|' ⍴⍨ ≢
AddHorizontals ← 1 ⊖ CreateVertical , '-' ⍪⍣2 ↑
{
    ⍵ ≡ ∊⍵: ⍉ ⍪ ⍉ ⍕ ⍵
    CloseBox ⊃ ,/ AddHorizontals¨ ↓ ↑ ↓¨ ∇¨ ⍵
}

Now let me explain each function:

CloseBox takes a table and returns the same table, but with the table's first column appended on the right of the table. Thus, given the 1-by-3 table XYZ, this function returns the 1-by-4 table XYZX, as follows:
 the argument (lit. what is on the right)
, prepended to
⊣/ the leftmost column (lit. the left-reduction of each row)

CreateVertical takes a table and returns the a string consisting of the characters which would fit |s on the sides of the table, but with two +s prepended to match two rows of -. Eventually the table will be cyclically rotated one row to get a single +---... row above and below. Thus, given any three row table, this function returns ++|||, as follows:
'++' , two pluses prepended to
'|' ⍴⍨ a stile reshaped by
 the (rows') tally of the argument

AddHorizontals takes a list-of-lists, makes it into a table, adds two rows of -s on top, adds the corresponding left edge characters on the left, then rotates one row to the bottom, so that the table has a border on the top, left, and bottom. As follows:
1 ⊖ rotate one row (the top row goes to the bottom) of
CreateVertical , the string ++|||... prepended (as a column) to
'-' ⍪⍣2 minus added twice to the top of
 the argument transformed from list-of-lists to table

{The anonymous function}: If the argument is a simple (not nested) list, make it into a character table (thus, given the 3-element list 1 2 3, this function returns the visually identical 1-by-five character table 1 2 3). If the argument is not a simple list, ensure the elements are simple character tables; pad them to equal height; frame each on their top, bottom, and left; combine them; and finally take the very first column and add it on the right. As follows:
{ begin the definition of an anonymous function
  ⍵ ≡ ∊⍵: if the argument is identical to the flattened argument (i.e. it is a simple list), then:
    transpose the
    columnized
    transposed
   ⍕ ⍵ stringified argument; else:
  CloseBox Add the leftmost column to the right of
  ⊃ ,/ the disclosed (because reduction encloses) concatenated-across
  AddHorizontals¨ add -s on top and bottom of each of
  ↓ ↑ ↓¨ the padded-to-equal-height* of
  ∇¨ ⍵  this anonymous function applied to each of the arguments
} end the definition of the anonymous function
* Lit. make each table into a list-of-lists, combine the lists-of-lists (padding with empty strings to fill short rows) into a table, then split the table into a list of lists-of-lists

Adám

Posted 2016-10-22T19:32:01.890

Reputation: 37 779

7

JavaScript (ES6), 223 203 bytes

f=(a,g=a=>a[0].map?`<${a.map(g).join`|`}>`:a.join` `,s=g([a]),r=[s],t=s.replace(/<[ -9|]*>|[ -9]/g,s=>s[1]?s.replace(/./g,c=>c>`9`?`+`:`-`):` `))=>t<`+`?r.join`\n`.replace(/<|>/g,`|`):f(a,g,t,[t,...r,t])

Port of @MitchSchwartz's Ruby solution. Previous version which worked by recursively wrapping the arrays (and therefore worked for arbitrary content, not just integers):

f=(...a)=>a[0]&&a[0].map?[s=`+${(a=a.map(a=>f(...a))).map(a=>a[0].replace(/./g,`-`)).join`+`}+`,...[...Array(Math.max(...a.map(a=>a.length)))].map((_,i)=>`|${a.map(a=>a[i]||a[0].replace(/./g,` `)).join`|`}|`),s]:[a.join` `]

Note: Although I'm using the spread operator in my argument list, to obtain the desired output, provide a single parameter of the original array rather then trying to spread the array; this has the effect of wrapping the output in the desired outer box. Sadly the outer box costs me 18 bytes, and space-separating the integers costs me 8 bytes, otherwise the following alternative visualisation would suffice for 197 bytes:

f=a=>a.map?[s=`+${(a=a.map(f)).map(a=>a[0].replace(/./g,`-`)).join`+`}+`,...[...Array(Math.max(0,...a.map(a=>a.length)))].map((_,i)=>`|${a.map(a=>a[i]||a[0].replace(/./g,` `)).join`|`}|`),s]:[``+a]

Neil

Posted 2016-10-22T19:32:01.890

Reputation: 95 035

Does this handle empty arrays? I receive an error Cannot read property 'map' of undefined for empty arrays such as []. For [1,2,[]], the last subarray isn't displayed for me. – miles – 2016-10-24T10:50:16.913

@miles Sorry, I'd forgotten to check out the test cases, and those now all work. You haven't specified the output for [1,2,[]] because your examples only show arrays containing either integers or arrays but not both. – Neil – 2016-10-24T11:02:53.710

Great. Also never mind that one, I didn't cover it in the test cases and the problem will be simpler (since yours is the only working entry so far) if each array is homogenous. – miles – 2016-10-24T11:13:00.940

3

Ruby, 104 bytes

->s{r=s=s.gsub'}{',?|
r=[s,r,s]*$/while s=s.tr('!-9',' ').gsub!(/{[ |]*}/){$&.tr' -}','-+'}
r.tr'{}',?|}

Anonymous function that expects a string. For example, {{{{{4 3 2 1}}}}{{{3 2 1}}}{{2 1}}{1}} produces

+---------------------------------+
|+-------------+---------+-----+-+|
||+-----------+|         |     | ||
|||+---------+||+-------+|     | ||
||||+-------+||||+-----+||+---+| ||
|||||4 3 2 1||||||3 2 1||||2 1||1||
||||+-------+||||+-----+||+---+| ||
|||+---------+||+-------+|     | ||
||+-----------+|         |     | ||
|+-------------+---------+-----+-+|
+---------------------------------+

You can use this code for testing:

f=->s{r=s=s.gsub'}{',?|
r=[s,r,s]*$/while s=s.tr('!-9',' ').gsub!(/{[ |]*}/){$&.tr' -}','-+'}
r.tr'{}',?|}

a=[]

a<<'[1, 2, 3]'
a<<'[[1, 2, 3], [4, 5], [6, 7, 8]]'
a<<'[[[1, 2, 3], [4, 5]], [6, 7, 8]]'
a<<'[]'
a<<'[[], []]'
a<<'[[], [1], [], [2], [], [3], []]'
a<<'[[[[[0]]]]]'
a<<'[[[[[4, 3, 2, 1]]]], [[[3, 2, 1]]], [[2, 1]], [1]]'

a.map{|s|s.gsub! '], [','}{'
s.tr! '[]','{}'
s.gsub! ',',''
puts s
puts f[s],''}

This starts from the middle row and works outwards. First, instances of }{ are replaced with |. Then, while there are still braces, all innermost {...} strings are transformed into the appropriate +- sequences while characters other than |{} are turned into spaces. At the end, the intermediate braces are turned into pipes.

Mitch Schwartz

Posted 2016-10-22T19:32:01.890

Reputation: 4 899

I took some liberties with the apparently lenient input formatting requirements. The code can be easily modified to handle a different input format, if required. – Mitch Schwartz – 2016-11-01T23:06:35.217

Receiving poorly thought out comments is one of the great joys of participating on this site. – Mitch Schwartz – 2016-11-08T02:02:53.097

3

Brainfuck, 423 bytes

->>+>>,[[>+>+<<-]+++++[>--------<-]>[<+>-[[-]<-]]>[[-]<<[>>>>+<<<<<<-<[>-<-]>>>-
]<<<[-<<<<<<-<]>+>>>]<<<[>>+>>>>>+<<<<<<<-]>>>>>>>>>,]<<+[<<,++>[-[>++<,<+[--<<<
<<<<+]>]]<[-<+]->>>>[<++<<[>>>>>>>+<<<<<<<-]>>>-[<++>-[>>>>+<<<<<++<]<[<<]>]<[>>
+<<<<]>>>+>+>[<<<-<]<[<<]>>>>->+>[-[<-<-[-[<]<[<++<<]>]<[<++++<<]>]<[>+<-[.<<<,<
]<[<<]]>]<[-<<<<<]>>[-[<+>---[<<++>>+[--[-[<+++++++<++>>,]]]]]<+++[<+++++++++++>
-]<-.,>>]>>>>+>>>>]<<-]

Formatted with some comments:

->>+>>,
[
  [>+>+<<-]
  +++++[>--------<-]
  >
  [
    not open paren
    <+>-
    [
      not paren
      [-]<-
    ]
  ]
  >
  [
    paren
    [-]
    <<
    [
      close paren
      >>>>+<<<<
      <<-<[>-<-]>>>
      -
    ]
    <<<
    [
      open paren directly after close paren
      -<<<<<<-<
    ]
    >+>>>
  ]
  <<<[>>+>>>>>+<<<<<<<-]>>>
  >>>>>>,
]
<<+
[
  <<,++>
  [
    -
    [
      >++<
      ,<+[--<<<<<<<+]
      >
    ]
  ]
  <[-<+]
  ->>>>
  [
    <++<<[>>>>>>>+<<<<<<<-]>>>-
    [
      at or before border
      <++>-
      [
        before border
        >>>>+<<<<
        <++<
      ]
      <[<<]
      >
    ]
    <
    [
      after border
      >>+<<
      <<
    ]
    >>>+>+>
    [
      column with digit or space
      <<<-<
    ]
    <[<<]
    >>>>->+>
    [
      middle or bottom
      -
      [
        bottom
        <-<-
        [
          at or before border
          -
          [
            before border
            <
          ]
          <
          [
            at border
            <++<<
          ]
          >
        ]
        <
        [
          after border
          <++++<<
        ]
        >
      ]
      <
      [
        middle
        >+<
        -[.<<<,<]
        <[<<]
      ]
      >
    ]
    <[-<<<<<]
    >>
    [
      border char or space
      -
      [
        not space
        <+>---
        [
          not plus
          <<++>>
          +
          [
            --
            [
              -
              [
                pipe
                <+++++++<++>>,
              ]
            ]
          ]
        ]
      ]
      <+++[<+++++++++++>-]<-.,>>
    ]
    > >>>+>>>>
  ]
  <<-
]

Try it online.

Expects input formatted like (((((4 3 2 1))))(((3 2 1)))((2 1))(1)) with a trailing newline, and produces output of the form:

+---------------------------------+
|+-------------+---------+-----+-+|
||+-----------+|+-------+|+---+| ||
|||+---------+|||+-----+|||   || ||
||||+-------+|||||     ||||   || ||
|||||4 3 2 1||||||3 2 1||||2 1||1||
||||+-------+|||||     ||||   || ||
|||+---------+|||+-----+|||   || ||
||+-----------+|+-------+|+---+| ||
|+-------------+---------+-----+-+|
+---------------------------------+

The basic idea is to calculate which character to print based on the depth of nesting. The output format is such that the row index of a box's top border is equal to the corresponding array's depth, with symmetry across the middle row.

The tape is divided into 7-cell nodes, with each node representing a column in the output.

The first loop consumes the input and initializes the nodes, keeping track of depth and whether the column corresponds to a parenthesis (i.e., whether the column contains a vertical border), and collapsing occurrences of )( into single nodes.

The next loop outputs one row per iteration. Within this loop, another loop traverses the nodes and prints one character per iteration; this is where most of the work takes place.

During the initialization loop, the memory layout of a node at the beginning of an iteration is

x d 0 c 0 0 0

where x is a boolean flag for whether the previous char was a closing parenthesis, d is depth (plus one), and c is the current character.

During the character printing loop, the memory layout of a node at the beginning of an iteration is

0 0 d1 d2 c p y

where d1 indicates depth compared with row index for top half; d2 is similar to d1 but for bottom half; c is the input character for that column if digit or space, otherwise zero; p indicates phase, i.e. top half, middle, or bottom half; and y is a flag that gets propagated from left to right, keeping track of whether we have reached the middle row yet. Note that since y becomes zero after processing a node, we can use the y cell of the previous node to gain more working space.

This setup allows us to avoid explicitly calculating the max depth during the initialization phase; the y flag is back-propagated to update the p cells accordingly.

There is a -1 cell to the left of the nodes to facilitate navigation, and there is a cell to the right of the nodes that keeps track of whether we have printed the last row yet.

Mitch Schwartz

Posted 2016-10-22T19:32:01.890

Reputation: 4 899

2

Ruby, 245 241 bytes

The overhead needed to wrap everything in boxes as well as align everything is pretty heavy...

Outputs arrays of strings, with one string per line, as per the spec. Bottom-aligned instead of the top-aligned sample test cases because it saves 1 byte.

Try it online!

V=->a{a==[*a]?(k=a.map(&V);k[0]==[*k[0]]?[h=?++?-*((k.map!{|z|z[1,0]=[' '*~-z[0].size+?|]*(k.map(&:size).max-z.size);z};f=k.shift.zip(*k).map{|b|?|+b.reduce{|r,e|r+e[1..-1]}+?|})[0].size-2)+?+,*f,h]:[h="+#{?-*(f=k*' ').size}+",?|+f+?|,h]):a}

Value Ink

Posted 2016-10-22T19:32:01.890

Reputation: 10 608

@Adám it's fixed now. Will try my best to optimize further later... – Value Ink – 2016-10-31T21:12:24.937

Nice.First answer with bottom alignment. :-) – Adám – 2016-10-31T22:05:01.333

2

PHP+HTML, not competing (170 141 135 130 bytes)

saved 29 bytes inspired by SteeveDroz

<?function p($a){foreach($a as$e)$r.=(is_array($e)?p($e):" $e");return"<b style='border:1px solid;float:left;margin:1px'>$r</b>";}

not competing because it´s no ascii output and because I let the browser do all the interesting work

Titus

Posted 2016-10-22T19:32:01.890

Reputation: 13 814

1You can make <b> tags instead of <div> and you don't need to specify the color of the border. (Saving 9 bytes) – SteeveDroz – 2016-10-31T15:30:02.970

You don't need to put a <tag> at all, just display the output as plain text, that will save a lot of bytes (80 bytes for the whole code after HTML removing) – ClementNerma – 2016-11-01T09:35:58.950

@SteeveDroz With <b>, I can also remove the white-space attribute, saving another 19 bytes. great! And I can replace padding with margin – Titus – 2016-11-01T10:05:25.290

2

JavaScript (ES6), 221

A non recursive function returning an array of strings (still using a recursive subfunction inside)

a=>[...(R=(a,l)=>a[r[l]='',0]&&a[0].map?'O'+a.map(v=>R(v,l+1))+'C':a.join` `)([a],l=-1,r=[],m='')].map(c=>r=r.map(x=>x+v[(k<0)*2+!k--],k=l,1/c?v='-- ':(v='-+|',c>'C'?k=++l:c>','&&--l,c='|'),m+=c))&&[...r,m,...r.reverse()]

This works in 2 steps.

Step 1: recursively build a string representation of the nested input array. Example:

[[[1, 2, 3], [],[4, 5]], [6, 7, 8]] -> "OOO1 2 3,,4 5C,6 7 8CC"

O and C mark open and close subarray. Simple numeric subarrays are rendered with the elements separated by space, while if array members are subarrays they are separated by commas. This string keeps track of the multilevel structure of the input array, while I can get the middle row of the output just replacing OC, with |. While recursively building this temp string, I also find the max depth level and initialize an array of empty strings that will contain the half top part of the output.
Note: the outer box is tricky, I nest the input inside another outer array, then I have drop the first row of output that is not needed

Step 2: scan the temp string and build the output

Now I have an array of empty strings, one for each level. I scan the temp string, keeping track of the current level, that increases for each O and decreases for each C. I visualize this like that:

[[[1, 2, 3], [],[4, 5]], [6, 7, 8]]

OOO1 2 3,,4 5C,6 7 8CC
+                    +
 +            +     +
  +     ++   +
|||1 2 3||4 5||6 7 8||

The plus the goes up and down follow the current level

For each char, I add a character to every row of output, following the rules:
- if digit or space, put a '-' at the current level and below, put a space above
- else, put a '+' at the current level, put a '-' if below and put a '|' if above

OOO1 2 3,,4 5C,6 7 8CC
+--------------------+
|+------------+-----+|
||+-----++---+|     ||
|||1 2 3||4 5||6 7 8||

During the temp scan, I also build the middle row replacing OC, with |

At the end of this step, I have the top half and the middle row, I only have to mirror the top to get the bottom half and I'm done

Less golfed, commented code

a=>{
   r = []; // output array
   R = ( // recursive scan function
     a, // current subarray 
     l  // current level
   ) => (
     r[l] = '', // element of r at level r, init to ""
     a[0] && a[0].map // check if it is a flat (maybe empty) array or an array of arrays
     ? 'O'+a.map(v=>R(v,l+1))+'C' // mark Open and Close, recurse
     : a.join` ` // just put the elements space separated
   );
   T = R([a],-1)]; // build temp string
   // pass the input nested in another array 
   // and start with level -1 , so that the first row of r will not be visible to .map

   // prepare the final output
   m = '' // middle row, built upon the chars in T
   l = -1 // starting level
   [...T].map(c => // scan the temp string
         {
            k = l; // current level
            1/c // check if numeric or space
             ? v = '-- ' // use '-','-',' '
             : (
                 v = '-+|', // use '-','+','|'
                 c > 'C' 
                   ? k=++l // if c=='O', increment level and assign to k
                   : c>'A'&&--l, // if c=='C', decrement level (but k is not changed)
                 c='|' // any of O,C,comma must be mapped to '|'
               );
            m += c; // add to middle row
            r = r.map( (x,i) => // update each output row
                       // based on comparation between row index and level
                       // but in golfed code I don't use the i index
                       // and decrement l at each step  
                       x + v[(k<i)*2+!(k-i)]
                     )
         })
   // almost done!  
   return [...r,m,...r.reverse()]

)

Test

F=
a=>[...(R=(a,l)=>a[r[l]='',0]&&a[0].map?'O'+a.map(v=>R(v,l+1))+'C':a.join` `)([a],l=-1,r=[],m='')].map(c=>r=r.map(x=>x+v[(k<0)*2+!k--],k=l,1/c?v='-- ':(v='-+|',c>'C'?k=++l:c>','&&--l,c='|'),m+=c))&&[...r,m,...r.reverse()]

out=x=>O.textContent = x+'\n'+O.textContent

;[[1,2,3]
,[[[1, 2, 3], [4, 5]], [6, 7, 8]]
,[]
,[[], []]
,[[], [1], [], [2], [], [3], []]
,[[[[[0]]]]]
,[[[[[4, 3, 2, 1]]]], [[[3, 2, 1]]], [[2, 1]], [1]]
].forEach(t=>
  out(JSON.stringify(t)+'\n'+F(t).join`\n`+'\n')
)  

function update()
{
  var i=eval(I.value)
  out(JSON.stringify(i)+'\n'+F(i).join`\n`+'\n')
}

update()
#I { width:90%}
<input id=I value='[[[1, 2, 3], [],[4, 5]], [6, 7, 8]]' oninput='update()'>
<pre id=O></pre>

edc65

Posted 2016-10-22T19:32:01.890

Reputation: 31 086

1

PHP, 404 Bytes

All solutions works with maximum depth of the array lesser then 10. for greater values the depth must store in an array and not in a string.

<?foreach(str_split(json_encode($_GET[a]))as$j){$j!="]"?:$c--;$r=($j==",")?($l=="]"?"":" "):$j;$r=$r=="]"?"|":$r;$r=$r=="["?($v=="]"?"":"|"):$r;if($r!=""){$n.=$r;$d.=+$c;}$v=$l;$l=$j;$j!="["?:$c++;$m>=$c?:$m=$c;}for($x=0;$x<strlen($n);$x++)for($y=0;$y<$m;$y++)$z[$y].=$y==$d[$x]&&$n[$x]=="|"?"+":($y<$d[$x]?"-":($y>$d[$x]&&$n[$x]=="|"?"|":" "));echo join("\n",$z),"\n$n\n".(join("\n",array_reverse($z)));

Expanded

foreach(str_split(json_encode($_GET[a]))as$j){ # split JSON representation of the array
    $j!="]"?:$c--;
    $r=($j==",")?($l=="]"?"":" "):$j;
    $r=$r=="]"?"|":$r;
    $r=$r=="["?($v=="]"?"":"|"):$r;
    if($r!=""){
      $n.=$r;  # concanate middle string
      $d.=+$c; # concanate depth position
    }
    $v=$l;
    $l=$j;
    $j!="["?:$c++;
    $m>=$c?:$m=$c; # maximum depth of the array
}
for($x=0;$x<strlen($n);$x++)for($y=0;$y<$m;$y++)
$z[$y].=$y==$d[$x]&&$n[$x]=="|"?"+":($y<$d[$x]?"-":($y>$d[$x]&&$n[$x]=="|"?"|":" "));
# Build the strings before the middle string dependent of value middle string and depth 
echo join("\n",$z),"\n$n\n".(join("\n",array_reverse($z))); #Output

for 425 Bytes we can make this with REGEX

<?$n=($p=preg_filter)("#\]|\[#","|",$r=$p("#\],\[#","|",$p("#,(\d)#"," $1",json_encode($_GET[a]))));preg_match_all("#.#",$r,$e,256);foreach($e[0] as$f){$f[0]!="]"&&$f[0]!="|"?:$c--;$d.=+$c;$f[0]!="|"&&$f[0]!="["?:$c++;$m>=$c?:$m=$c;}for($x=0;$x<strlen($n);$x++)for($y=0;$y<$m;$y++)$z[$y].=$y==$d[$x]&&$n[$x]=="|"?"+":($y<$d[$x]?"-":($y>$d[$x]&&$n[$x]=="|"?"|":" "));echo join("\n",$z),"\n$n\n".(join("\n",array_reverse($z)));

Expanded

$r=preg_filter("#\],\[#","|",preg_filter("#,(\d)#"," $1",json_encode($_GET[a])));
preg_match_all("#.#",$r,$e,256);
$n=preg_filter("#\]|\[#","|",$r); # concanate middle string
foreach($e[0] as$f){
    $f[0]!="]"&&$f[0]!="|"?:$c--;
    $d.=+$c; concanate depth position
    $f[0]!="|"&&$f[0]!="["?:$c++;
    $m>=$c?:$m=$c; # maximum depth of the array
}
# similar to the other ways
for($x=0;$x<strlen($n);$x++)
for($y=0;$y<$m;$y++)
$z[$y].=$y==$d[$x]&&$n[$x]=="|"?"+":($y<$d[$x]?"-":($y>$d[$x]&&$n[$x]=="|"?"|":" "));
echo join("\n",$z),"\n$n\n".(join("\n",array_reverse($z)));

455 Bytes for a recursive solution

<?function v($x,$t=0,$l=1){global$d;$d.=$t;$s="|";$c=count($x);foreach($x as$k=>$v){if(is_array($v))$e=v($v,$t+1,$k+1==$c);else{$e=$v." "[$k+1==$c];$d.=str_pad("",strlen($e),$t+1);}$s.=$e;}$d.=$l?$t:"";$s.=$l?"|":"";return$s;}$n=v($_GET[a]);$m=max(str_split($d));for($x=0;$x<strlen($n);$x++)for($y=0;$y<$m;$y++)$z[$y].=$y==$d[$x]&&$n[$x]=="|"?"+":($y<$d[$x]?"-":($y>$d[$x]&&$n[$x]=="|"?"|":" "));echo join("\n",$z),"\n$n\n".(join("\n",array_reverse($z)));

Expanded

function v($x,$t=0,$l=1){
    global$d; # concanate depth position
    $d.=$t;
    $s="|";
    $c=count($x);
    foreach($x as$k=>$v){           
        if(is_array($v)){$e=v($v,$t+1,$k+1==$c);}
        else{$e=$v." "[$k+1==$c];$d.=str_pad("",strlen($e),$t+1);}
        $s.=$e;
    }
    $d.=$l?$t:"";
    $s.=$l?"|":"";
    return$s;
}
$n=v($_GET[a]); # concanate middle string
$m=max(str_split($d)); # maximum depth of the array
# similar to the other ways 
for($x=0;$x<strlen($n);$x++)
for($y=0;$y<$m;$y++)
$z[$y].=$y==$d[$x]&&$n[$x]=="|"?"+":($y<$d[$x]?"-":($y>$d[$x]&&$n[$x]=="|"?"|":" "));
echo join("\n",$z),"\n$n\n".(join("\n",array_reverse($z)));

Jörg Hülsermann

Posted 2016-10-22T19:32:01.890

Reputation: 13 026

>

  • $j!="]"?:$c--; -> $c-=$j=="]"; (-2). 2) ($l=="]"?"":" ") -> " "[$l==$j] (-5). Most probably similar substitutions in the second loop. 3) if($r!=""){$n.=$r;$d.=+$c;} -> $n.=$r;if($r>"")$d.=+$c; (-3). 4) $l=$j;$j!="["?:$c++; -> $c+="["==$l=$j; (-5). 5) $x=0 is not needed (-4). 6) for($y=0;$y<$m;$y++) -> for($y=$m;$y--;) (-4). 7) join("\n",$z),"\n$n\n".(join("\n",array_reverse($z))); -> join("\n",array_merge($z,[$n],array_reverse($z))); (-4) 8) unnecessary whitespace: foreach($e[0]as$f) (-1)
  • < – Titus – 2016-11-03T10:16:35.643

    start="9">

  • unecessary parentheses at ($j==",") (-2). 10) if($r>"")$d.=+$c; -> $d.=$r>""?+$c:""; (-0)
  • < – Titus – 2016-11-03T10:22:23.920

    recursive version:

    1. $d.=$l?$t; is obsolete (-10)
    2. $s.=$l?"|":"";return$s; -> return$s."|"[$l]; (-6).
    3. obsolete braces {$e=v($v,$t+1,$k+1==$c);} (-2).
    4. {$e=$v." "[$k+1==$c];$d.=str_pad("",strlen($e),$t+1);} -> $d.=str_pad("",strlen($e=$v." "[$k+1==$c]),$t+1); (-5).
    5. < – Titus – 2016-11-03T10:47:42.060