Disegnare un albero da un array


24

Dato un array possibilmente nidificato e non vuoto di numeri interi positivi a una cifra (non garantito univoco), emette la rappresentazione di arte ASCII come un albero, usando i caratteri del disegno a scatola ┌ ┴ ┐ ─ │ ┬ ┼. (Questi sono stati copiati dal codice pagina 437, ma è possibile utilizzare qualsiasi rappresentazione equivalente).

Ogni numero intero dell'array dovrebbe essere una foglia dell'albero. Gli elementi allo stesso livello profondo dell'array dovrebbero essere presenti allo stesso livello dell'albero. Tutti gli elementi devono essere separati da uno spazio sufficiente per essere distinti (spetta a te determinare quanto largo, minimo uno spazio tra).

Ad esempio, dato l'array [[1, [2]], [3, [4, 5]]], genera il seguente albero

 ┌─┴─┐
┌┴┐ ┌┴─┐
1 │ 3 ┌┴┐
  2   4 5

Per l'array [1, 2, 3]l'albero potrebbe apparire

┌─┼─┐
1 2 3

Ma l'array [[1, 2, 3]]sarebbe simile

  │
┌─┼─┐
1 2 3

Mentre l'array [1, [1, [1, [1]]]]potrebbe apparire

 ┌─┴┐
 1 ┌┴─┐
   1 ┌┴┐
     1 │
       1

Come esempio più complicato, [1, [[[2, 3], 4], 5]]potrebbe essere

┌┴───┐
1  ┌─┴┐
 ┌─┴┐ 5
┌┴┐ 4
2 3

o diverse altre varianti.


  • Input e output possono essere forniti con qualsiasi metodo conveniente .
  • È possibile stamparlo su STDOUT o restituirlo come risultato di una funzione.
  • È accettabile un programma completo o una funzione.
  • Qualsiasi quantità di spazio bianco estraneo è accettabile, purché i personaggi siano allineati in modo appropriato.
  • Sono vietate le scappatoie standard .
  • Si tratta di quindi si applicano tutte le normali regole del golf e vince il codice più breve (in byte).

[1,[[[2,3],4],5]]potrebbe essere un caso di test interessante poiché deve estendere artificialmente la radice in modo che la sottostruttura destra non entri in collisione con la sottostruttura sinistra.
Colpisci il

@Poke Aggiunto come esempio. Esistono diverse varianti per quel caso di test.
AdmBorkBork,

2
Il primo esempio per quel caso di test non può essere giusto. Ciò suggerisce che il secondo elemento s accanto 1è un array di 3 elementi: [2,3], 4e 5. Ma 4 e 5 non sono adiacenti.
Draco18s,

4
Mi assomiglia [1, [[[2, 3]], [4], 5]].
Neil,

Quale (se presente) di questi formati di input alternativi sarebbe accettabile?
Οurous

Risposte:


12

Python 3 , 400 393 390 byte

L=len
S,*K=' ┴┼│123456789'
def T(x):
 try:return[str(x+0)]
 except:
  z=[*map(T,x)];q=max(map(L,z))
  for p in z:p+=[S*L(p[0])]*(q-L(p))
  b=[S.join(a)for a in zip(*z)];t=b[0];l=L(t);s=0;e=L(z);r=[S]*l
  if e<2:return['│'.center(l),*b]
  for i in range(l):
   if t[i]in K:s+=1;r[i]='┬┌┐'[(s<e)-(s>1)]
   elif 0<s<e:r[i]='─'
  c=l//2;r[c]=K[r[c]=='┬'];return[''.join(r),*b]

Restituisce un elenco di stringhe dall'alto verso il basso.

EDIT 1: Tagliato 7 byte evitando la duplicazione di ┴┼(risparmio netto di 2 byte), tagliando 0 da una stringa, cambiando il modo in cui i caratteri di disegno sono selezionati ┬┌┐(usa <invece di ==) e sostituendo un L(z)Mi mancava cone

EDIT 2: -2 byte grazie agli ovs e -1 byte grazie a Kevin Cruijssen

Provalo online!

Ungolfed

def layer(item):
    if isinstance(item, int):
        return [str(item)]
    else:
        subs = [layer(sub) for sub in item]
        longest = max(map(len, subs))
        for sub in subs:
            sub += [' ' * len(sub[0])] * (longest - len(sub))
        below = [' '.join(l) for l in zip(*subs)]
        top = below[0]
        l = len(top)
        if len(subs) == 1:
            return ['│'.center(l), *below]
        seen = 0
        expected = len(subs)
        builder = [' '] * l
        for i in range(l):
            c = top[i]
            if c in '┴┼│123456789':
                seen += 1
                if seen == 1:
                    builder[i] = '┌'
                elif seen == expected:
                    builder[i] = '┐'
                else:
                    builder[i] = '┬'
            elif 0 < seen < expected:
                builder[i] = '─'
        center = l // 2
        if builder[center] == '┬':
            builder[center] = '┼'
        else:
            builder[center] = '┴'
        return [''.join(builder), *below]

Costruisce un albero dalle foglie, uno strato alla volta.


2
Ho aggiunto i casi di test al tuo link TIO Provalo online!
pizzapants184

Bella risposta! È possibile ridurre questo da due byte assegnando lo spazio per una variabile in questo modo: S,*K=' ┴┼│123456789'.
Ov

1
e==1può essere e<2quello di salvare un byte (non credo che possa mai essere 0, poiché la sfida afferma che l'input è non vuoto - e gli input vuoti max(map(L,z))in quel caso non avrebbero già funzionato ).
Kevin Cruijssen il

3

Pulito , 544 506 byte

Gli escape vengono utilizzati per evitare UTF-8 non valido su SE / TIO ma vengono conteggiati come un byte poiché sono letterali validi

import StdEnv,Data.List;::T=I Int|L[T];$l#m= @l#k=map maxList(transpose m)=flatlines[[last[' ':[(\_|v<0|w<[j]|q>hd w|q<last w|any((==)q)w|q==j='\305'='\302'|q==j='\301'='\304'='\277'='\332'='\263'=toChar v+'0')0\\[v,r,j:w]<-m|r/2==p&&q>=hd w&&q<=last w]]\\q<-[0..k!!3]]\\p<-[0..k!!1]];@(L l)#p=twice(\p=[[v,r+1:[e+sum([2\\[v:_]<-i|0<=v]++zipWith(\c j=j!!2-c!!3)t(takeWhile(\[z:_]=v+z< -1)(tl t)))-x!!1\\e<-x]]\\i<-inits p&t<-tails p&[v,r:x]<-p])(concatMap@l)#g=[g\\[_,2,g:_]<-p]=[[-1,0,(hd g+last g)/2:g]:p];@(I i)=[[i,0,0,0]];

Provalo online!

Accetta input nel formato L[I 3, L[I 4, I 5], I 2]..

Collega gli alberi dal basso verso l'alto, da sinistra a destra, quindi regola le distanze da destra a sinistra.

Prettificato, sorta di:

import StdEnv, Data.List;
:: T = I Int | L [T];
$ l
    #m = @l
    #k = map maxList (transpose m)
    = flatlines [
        [
            last[
                ' ':
                [
                    if(v < 0)
                        if(w < [j])
                            if(q > hd w)
                                if(q < last w)
                                    if(any ((==) q) w)
                                        (
                                            if(q == j)
                                                '\305'
                                                '\302'
                                        )(
                                            if(q == j)
                                                '\301'
                                                '\304'
                                        )
                                    '\277'
                                '\332'
                            '\263'
                        (toChar v + '0')
                    \\ [v, r, j: w] <- m
                    | r/2 == p && q >= hd w && q <= last w
                ]
            ]
            \\ q <- [0..k!!3]
        ]
        \\p<-[0..k!!1]
    ];
@ (L l)
    #p = twice
        ( \p
            = [
                [
                    v, r + 1:
                    map
                        (
                            (+)
                            (
                                sum [2 \\ [v: _] <- i| 0 <= v]
                                + sum (
                                    zipWith
                                        (
                                            \[_, _, _, c: _] [_, _, j: _] = j - c
                                        )
                                        t
                                        (
                                            takeWhile (\[v: _] = v < 0) (tl t)
                                        )
                                ) * (1 - sign (v + 1))
                                - x!!1
                            )
                        )
                        x
                ]
            \\ i <- inits p
            &  t <- tails p
            &  [v, r: x] <- p
            ]
        )
        (concatMap @ l)
    #g = [g \\ [_, 2, g: _] <- p]
    =[[-1, 0, (hd g + last g)/2: g]: p];
@ (I i) = [[i, 0, 0, 0]];

3

Carbone , 127 123 byte

↶≔⟦⟦θ⟧⟧ηFη«≔⊟ιζ¿⁼Iζ⪫⟦ζ⟧ω⊞υ⊞OιζFLζ⊞η⁺ι⟦⊖Lζκ§ζκ⟧»Wυ«≔⌊υι≔Φυ¬⁼κιυJ±⊗Lυ⊘⊖LιI⊟ιWι«≔⊟ιζ¿ζ«←§┐┬‹ζ⊟ιW⁼KKψ←─≔⁰ι»¿⊟ι┌¶┴¦│

Provalo online! Il collegamento è alla versione dettagliata del codice. Spiegazione:

Cambia la direzione di disegno predefinita in su poiché non disegniamo nulla a destra.

≔⟦⟦θ⟧⟧η

Il primo passo è quello di convertire la rappresentazione di vettore annidato in una rappresentazione dell'indice che è un elenco di tutte le voci insieme con gli indici dei sottoarray, ad esempio per l'ingresso q=[1, [[[2, 3]], [4], 5]]della 5è q[1][2]e pertanto l'elenco che vogliamo è 1, 2. Iniziamo con una singola voce da elaborare, che è un elenco contenente un elenco degli indici correnti (ovvero nessuno finora) e l'input originale.

Fη«

Passa sopra gli array mentre li elaboriamo. (Convenientemente, Carbone continuerà a scorrere su un elenco se si preme su di esso durante l'iterazione.)

≔⊟ιζ

Ottieni l'elaborazione dell'array successivo.

¿⁼Iζ⪫⟦ζ⟧ω

È davvero uno scalare piuttosto che un array?

⊞υ⊞Oιζ

In tal caso, l'elenco che avevamo effettivamente appartiene all'elenco finale degli elenchi di indici.

FLζ

In caso contrario, scorrere su ogni elemento in questo array ...

⊞η⁺ι⟦⊖Lζκ§ζκ⟧»

... e salvalo con il suo nuovo elenco di indici finora per ulteriori elaborazioni. Viene inoltre salvato l'indice massimo dell'array che viene utilizzato in casi speciali l'ultimo elemento dell'array.

Wυ«

Ora siamo pronti per scorrere l'elenco degli elenchi di indici. Tuttavia, l'elenco non è in ordine lessicografico, quindi non possiamo iterarlo direttamente.

≔⌊υι

Trova l'elemento successivo in ordine lessicografico.

≔Φυ¬⁼κιυ

Rimuovilo dall'elenco.

J±⊗Lυ⊘⊖Lι

Passa alla posizione dello scalare nell'output. Possiamo calcolare questo dato che possiamo tenere conto del numero di scalari che produciamo e conosciamo anche il numero di voci nel suo elenco di indici.

I⊟ι

In realtà stampa lo scalare.

Wι«

Scorri le voci nell'elenco degli indici. Ancora una volta, questa non è una semplice iterazione, perché le voci sono in coppia e dobbiamo anche essere in grado di uscire dal ciclo.

≔⊟ιζ

Estrarre l'indice successivo dall'elenco.

¿ζ«

Se questo non è il primo elemento nell'elenco ...

←§┐┬‹ζ⊟ι

... quindi stampa o a seconda che questo sia l'ultimo elemento nell'elenco ...

W⁼KKψ←─

... e stampa abbastanza s per riempire fino alla voce precedente a questo livello ...

≔⁰ι»

... e cancella la variabile per uscire dal ciclo dal momento che abbiamo finito qui.

¿⊟ι┌¶┴

Altrimenti se questo è (il primo elemento di) un elenco di più elementi, allora stampa il ┌┴, lasciando il cursore sopra il per gestire il genitore di questo livello.

¦│

Altrimenti se questo è un elenco di 1 elemento, basta stampare un e spostarsi di una riga per gestire il genitore di questo livello.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.