Visualizar una matriz

26

Dada una matriz de cualquier profundidad, dibuje su contenido con bordes +-|alrededor de cada submatriz. Esos son los caracteres ASCII para más, menos y tubería vertical.

Por ejemplo, si la matriz es [1, 2, 3], dibuje

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

Para una matriz anidada como [[1, 2, 3], [4, 5], [6, 7, 8]], dibujar

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

Para una matriz irregular como [[[1, 2, 3], [4, 5]], [6, 7, 8]], dibujar

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

Observe que hay más espacio después del dibujo [6, 7, 8]. Puede dibujar el contenido en la línea superior, central o inferior, pero cualquiera que elija, debe ser coherente.

Este desafío fue inspirado por el verbo en recuadro< de J.

Reglas

  • Este es el por lo que gana el código más corto.
  • Los componentes que resuelven esto no están permitidos.
  • La matriz de entrada contendrá solo valores enteros no negativos o matrices. Cada matriz será homogénea, lo que significa que sus elementos serán solo matrices o enteros, pero nunca una combinación de ambos.
  • Cada submatriz puede estar anidada a cualquier profundidad.
  • La salida puede ser como una cadena o como una matriz de cadenas donde cada cadena es una línea de salida.

Casos de prueba

[]
++
||
++

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

[[], [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|||||+-----+||     | ||
||||+-------+|||+-------+|     | ||
|||+---------+||         |     | ||
||+-----------+|         |     | ||
|+-------------+---------+-----+-+|
+---------------------------------+
millas
fuente
Si mi idioma no tiene matrices anidadas, ¿puedo ignorar la definición del tipo de datos?
ThreeFx
1
@ThreeFx También puede tomar la entrada como una cadena que representa la matriz anidada
millas del
Eso es REALMENTE ineficiente (en Haskell). Tendría que analizar los números manualmente y así sucesivamente. En ese caso, sería más corto definir y usar el tipo de datos.
ThreeFx
@ThreeFx O podría rellenar la matriz con valores centinela, como -1porque también limité los enteros para que no sean negativos. Entonces solo tendría que limpiar la salida de esos valores no válidos.
millas
1
@MitchSchwartz Claro, tome la entrada en una tupla anidada o en cualquier formato nativo de su idioma. Su salida está bien siempre y cuando permanezca constante. Los números enteros se pueden dibujar en la parte superior, central o inferior, y los cuadros pueden estar en la parte superior, central, inferior o estirada para completar su espacio como en su ejemplo.
millas

Respuestas:

4

Dyalog APL , 56 bytes

Gracias a ngn por ayudar a eliminar aproximadamente un tercio de los bytes.

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

TryAPL

Defina la función , luego ejecute cada caso de prueba y compárelo con la ]Displayutilidad incorporada .
[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]]

Explicación

En general, esta es una función anónima {...}sobre un cerramiento . El último solo agrega otro nivel de anidación, lo que hace que el primero agregue un marco externo.

La función anónima con espacios en blanco ( es el separador de sentencias):

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

Aquí está de nuevo, pero con funciones de utilidad separadas:

CloseBox   , ⊣/
CreateVertical  '++' , '|' ⍴⍨ 
AddHorizontals  1  CreateVertical , '-' ⍪⍣2 
{
      ∊⍵:     
    CloseBox  ,/ AddHorizontals¨   ↓¨ ∇¨ 
}

Ahora déjame explicarte cada función:

CloseBoxtoma una tabla y devuelve la misma tabla, pero con la primera columna de la tabla agregada a la derecha de la tabla. Por lo tanto, dada la tabla 1 por 3 XYZ, esta función devuelve la tabla 1 por 4 XYZX, de la siguiente manera:
 el argumento (encendido lo que está a la derecha)
, antepuesto a
⊣/ la columna más a la izquierda (encendido la reducción izquierda de cada fila)

CreateVerticaltoma una tabla y devuelve una cadena que consta de los caracteres que encajarían |en los lados de la tabla, pero con dos +s antepuestos para que coincidan con dos filas de -. Finalmente, la tabla se rotará cíclicamente una fila para obtener una sola +---...fila arriba y abajo. Por lo tanto, dada cualquier tabla de tres filas, esta función regresa de la ++|||siguiente manera:
'++' , dos ventajas más antepuestas a
'|' ⍴⍨ un estilo reformado por
 la cuenta (filas) del argumento

AddHorizontalstoma una lista de listas, la convierte en una tabla, agrega dos filas de -s en la parte superior, agrega los caracteres de borde izquierdo correspondientes a la izquierda, luego gira una fila hacia abajo, de modo que la tabla tenga un borde en la parte superior , izquierda y abajo. De la siguiente manera:
1 ⊖ gire una fila (la fila superior va al final) de
CreateVertical , la cadena ++|||...antepuesta (como una columna) para
'-' ⍪⍣2 agregar menos dos veces a la parte superior del
 argumento transformado de la lista de listas a la tabla

{La función anónima }: si el argumento es una lista simple (no anidada), conviértala en una tabla de caracteres (por lo tanto, dada la lista de 3 elementos 1 2 3, esta función devuelve la tabla de caracteres visualmente idéntica de 1 por cinco 1 2 3). Si el argumento no es una lista simple, asegúrese de que los elementos sean tablas de caracteres simples; acolcharlos a la misma altura; enmarca cada uno en su parte superior, inferior e izquierda; combinarlos y finalmente tome la primera columna y agréguela a la derecha. De la siguiente manera:
{ comience la definición de una función anónima
  ⍵ ≡ ∊⍵:si el argumento es idéntico al argumento aplanado (es decir, es una lista simple), luego:
    transponga el  argumento
    stringificado
    transpuesto en
   ⍕ ⍵columnas; más:
  CloseBox agregue la columna más a la izquierda a la derecha de
  ⊃ ,/ los
  AddHorizontals¨ agregados revelados (porque la reducción encierra) se concatenan -en la parte superior e inferior de cada una de
  ↓ ↑ ↓¨ las
  ∇¨ ⍵  funciones acolchadas a la misma altura * de esta función anónima aplicada a cada uno de los argumentos
} finaliza la definición de la función anónima
* Lit. convierta cada tabla en una lista de listas, combine las listas de listas (relleno con cadenas vacías para llenar filas cortas) en una tabla, luego divida la tabla en una lista de listas de listas

Adán
fuente
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])

Puerto de la solución Ruby de @ MitchSchwartz. Versión anterior que funcionaba envolviendo recursivamente las matrices (y, por lo tanto, funcionaba para contenido arbitrario, no solo enteros):

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` `]

Nota: Aunque estoy usando el operador de propagación en mi lista de argumentos, para obtener el resultado deseado, proporcione un único parámetro de la matriz original en lugar de intentar distribuir la matriz; Esto tiene el efecto de envolver la salida en el cuadro exterior deseado. Lamentablemente, la caja externa me cuesta 18 bytes, y la separación del espacio de los enteros me cuesta 8 bytes, de lo contrario la siguiente visualización alternativa sería suficiente para 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
fuente
¿Esto maneja matrices vacías? Recibo un error Cannot read property 'map' of undefinedpara matrices vacías como []. Para [1,2,[]], el último subconjunto no se muestra para mí.
millas
@miles Lo siento, me había olvidado de revisar los casos de prueba, y ahora todos funcionan. No ha especificado la salida [1,2,[]]porque sus ejemplos solo muestran matrices que contienen enteros o matrices, pero no ambas.
Neil
Excelente. Además, no importa eso, no lo cubrí en los casos de prueba y el problema será más simple (ya que el suyo es la única entrada que funciona hasta ahora) si cada matriz es homogénea.
millas
3

Ruby, 104 bytes

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

Función anónima que espera una cadena. Por ejemplo, {{{{{4 3 2 1}}}}{{{3 2 1}}}{{2 1}}{1}}produce

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

Puede usar este código para probar:

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],''}

Esto comienza desde la fila del medio y funciona hacia afuera. Primero, las instancias de }{se reemplazan con |. Luego, si bien todavía hay llaves, todas las {...}cadenas más internas se transforman en las +-secuencias apropiadas , mientras que los caracteres que no sean |{}se convierten en espacios. Al final, los tirantes intermedios se convierten en tubos.

Mitch Schwartz
fuente
Me tomé algunas libertades con los requisitos de formato de entrada aparentemente indulgentes. El código se puede modificar fácilmente para manejar un formato de entrada diferente, si es necesario.
Mitch Schwartz el
Recibir comentarios mal pensados ​​es una de las grandes alegrías de participar en este sitio.
Mitch Schwartz el
3

Brainfuck, 423 bytes

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

Formateado con algunos comentarios:

->>+>>,
[
  [>+>+<<-]
  +++++[>--------<-]
  >
  [
    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
                <+++++++<++>>,
              ]
            ]
          ]
        ]
      ]
      <+++[<+++++++++++>-]<-.,>>
    ]
    > >>>+>>>>
  ]
  <<-
]

Pruébalo en línea.

Espera entradas formateadas como (((((4 3 2 1))))(((3 2 1)))((2 1))(1))con una nueva línea final y produce salidas de la forma:

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

La idea básica es calcular qué personaje imprimir en función de la profundidad de anidamiento. El formato de salida es tal que el índice de fila del borde superior de un cuadro es igual a la profundidad de la matriz correspondiente, con simetría en la fila central.

La cinta se divide en nodos de 7 celdas, y cada nodo representa una columna en la salida.

El primer bucle consume la entrada e inicializa los nodos, haciendo un seguimiento de la profundidad y si la columna corresponde a un paréntesis (es decir, si la columna contiene un borde vertical), y las ocurrencias de colapso )(en nodos individuales.

El siguiente ciclo genera una fila por iteración. Dentro de este bucle, otro bucle atraviesa los nodos e imprime un carácter por iteración; Aquí es donde tiene lugar la mayor parte del trabajo.

Durante el ciclo de inicialización, el diseño de memoria de un nodo al comienzo de una iteración es

x d 0 c 0 0 0

donde xes una bandera booleana para saber si el carácter anterior era un paréntesis de cierre, si des profundidad (más uno) y si ces el carácter actual.

Durante el ciclo de impresión de caracteres, el diseño de memoria de un nodo al comienzo de una iteración es

0 0 d1 d2 c p y

donde d1indica profundidad en comparación con el índice de fila para la mitad superior; d2es similar d1pero para la mitad inferior; ces el carácter de entrada para esa columna si es dígito o espacio, de lo contrario cero; pindica fase, es decir, mitad superior, media o mitad inferior; y yes una bandera que se propaga de izquierda a derecha, haciendo un seguimiento de si ya hemos llegado a la fila del medio. Tenga en cuenta que, dado que se yconvierte en cero después de procesar un nodo, podemos usar la ycelda del nodo anterior para ganar más espacio de trabajo.

Esta configuración nos permite evitar calcular explícitamente la profundidad máxima durante la fase de inicialización; la ybandera se propaga hacia atrás para actualizar las pceldas en consecuencia.

Hay una -1celda a la izquierda de los nodos para facilitar la navegación, y hay una celda a la derecha de los nodos que realiza un seguimiento de si ya hemos impreso la última fila.

Mitch Schwartz
fuente
2

PHP + HTML, no compite ( 170 141 135 130 bytes)

guardado 29 bytes inspirados en 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>";}

no compite porque no es una salida ASCII y porque dejo que el navegador haga todo el trabajo interesante

Titus
fuente
1
Puede hacer <b>etiquetas en lugar de <div>y no necesita especificar el color de la border. (Ahorro de 9 bytes)
SteeveDroz
No es necesario que coloque una <tag> en absoluto, solo muestre la salida como texto sin formato, eso ahorrará muchos bytes (80 bytes para todo el código después de la eliminación de HTML)
ClementNerma
@SteeveDroz Con <b>, también puedo eliminar el white-spaceatributo, ahorrando otros 19 bytes. ¡Excelente! Y puedo reemplazar paddingconmargin
Titus
2

JavaScript (ES6), 221

Una función no recursiva que devuelve una matriz de cadenas (aún utilizando una subfunción recursiva en el interior)

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()]

Esto funciona en 2 pasos.

Paso 1: construya recursivamente una representación de cadena de la matriz de entrada anidada. Ejemplo:

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

Oy Cmarque subarreglos de apertura y cierre. Las submatrices numéricas simples se representan con los elementos separados por espacio, mientras que si los miembros de la matriz son submatrices, se separan por comas. Esta cadena no pierde de vista la estructura de varios niveles de la matriz de entrada, mientras que yo puedo conseguir la fila del medio de la salida sólo la sustitución OC,con |. Mientras construyo recursivamente esta cadena temporal, también encuentro el nivel de profundidad máxima e inicializo una matriz de cadenas vacías que contendrán la mitad de la parte superior de la salida.
Nota: el cuadro externo es complicado, anido la entrada dentro de otra matriz externa, luego dejo caer la primera fila de salida que no es necesaria

Paso 2: escanee la cadena temporal y cree la salida

Ahora tengo una serie de cadenas vacías, una para cada nivel. Escaneo la cadena temporal, haciendo un seguimiento del nivel actual, que aumenta para cada uno Oy disminuye para cada uno C. Visualizo esto así:

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

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

El plus sube y baja siguiendo el nivel actual

Para cada carácter, agrego un carácter a cada fila de salida, siguiendo las reglas:
- si es un dígito o un espacio, ponga un '-' en el nivel actual y debajo, ponga un espacio arriba
- de lo contrario, ponga un '+' en el nivel actual, ponga un '-' si está debajo y ponga un '|' si arriba

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

Durante el escaneo temporal, también construyo la fila del medio reemplazando OC,con|

Al final de este paso, tengo la mitad superior y la fila central, solo tengo que reflejar la parte superior para obtener la mitad inferior y he terminado

Menos comentado, código comentado

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()]

)

Prueba

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
fuente
2

Ruby, 245 241 bytes

La sobrecarga necesaria para envolver todo en cajas y alinear todo es bastante pesada ...

Emite conjuntos de cadenas, con una cadena por línea, según la especificación. Casos de prueba de alineación inferior en lugar de alineación superior porque ahorra 1 byte.

Pruébalo en línea!

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}
Tinta de valor
fuente
@ Adám ya está arreglado. Haré mi mejor esfuerzo para optimizar aún más tarde ...
Value Ink
Nice.Primera respuesta con la alineación inferior. :-)
Adám
1

PHP, 404 bytes

Todas las soluciones funcionan con una profundidad máxima de la matriz menor que 10. para valores mayores, la profundidad debe almacenarse en una matriz y no en una cadena.

<?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)));

Expandido

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

por 425 Bytes podemos hacer esto con 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)));

Expandido

$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 para una solución recursiva

<?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)));

Expandido

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
fuente
1) $j!="]"?:$c--;-> $c-=$j=="]";(-2). 2) ($l=="]"?"":" ")-> " "[$l==$j](-5). Probablemente sustituciones similares en el segundo bucle. 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=0no es necesario (-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) espacios en blanco innecesarios: foreach($e[0]as$f)(-1)
Tito el
9) paréntesis innecesarios en ($j==",")(-2). 10) if($r>"")$d.=+$c;-> $d.=$r>""?+$c:"";(-0)
Tito el
versión recursiva: 1) $d.=$l?$t;está obsoleta (-10) 2) $s.=$l?"|":"";return$s;-> return$s."|"[$l];(-6). 3) llaves obsoletas {$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).
Tito el