Dessiner un arbre à partir d'un tableau

24

Étant donné un tableau éventuellement imbriqué et non vide d'entiers positifs à un chiffre (non garanti unique), affichez la représentation ASCII sous forme d'arbre, en utilisant les caractères de dessin de boîte ┌ ┴ ┐ ─ │ ┬ ┼. (Celles-ci ont été copiées à partir de la page de code 437, mais vous pouvez utiliser n'importe quelle représentation équivalente).

Chaque entier du tableau doit être une feuille de l'arbre. Les éléments situés au même niveau profondément dans le tableau doivent être présents au même niveau de l'arborescence. Tous les éléments doivent être séparés par suffisamment d'espaces pour être distincts (à vous de déterminer la largeur, au moins un espace entre les deux).

Par exemple, pour un tableau donné [[1, [2]], [3, [4, 5]]], affichez l'arborescence suivante

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

Pour le tableau, [1, 2, 3]l'arbre pourrait ressembler à

┌─┼─┐
1 2 3

Mais le tableau [[1, 2, 3]]ressemblerait

  │
┌─┼─┐
1 2 3

Bien que le tableau [1, [1, [1, [1]]]]puisse ressembler

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

À titre d’exemple plus complexe, [1, [[[2, 3], 4], 5]]pourrait être

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

ou plusieurs autres variantes.


  • L'entrée et la sortie peuvent être fournies par n'importe quelle méthode pratique .
  • Vous pouvez l'imprimer sur STDOUT ou le renvoyer en tant que résultat de fonction.
  • Un programme complet ou une fonction sont acceptables.
  • N'importe quelle quantité d'espace blanc étranger est acceptable, tant que les caractères s'alignent correctement.
  • Les failles standard sont interdites.
  • Il s'agit de donc toutes les règles de golf habituelles s'appliquent et le code le plus court (en octets) l'emporte.
AdmBorkBork
la source
[1,[[[2,3],4],5]]pourrait être un cas de test intéressant car il doit avoir la racine s'étendre artificiellement pour que le sous-arbre droit n'entre pas en collision avec le sous-arbre gauche.
Poke
@Poke Ajouté comme exemple. Il existe plusieurs variantes possibles pour ce cas de test.
AdmBorkBork
2
Le premier exemple de ce cas de test ne peut pas être exact. Cela suggère que le deuxième élément s à côté de l' 1est un tableau de 3 éléments: [2,3], 4, et 5. Mais 4 et 5 ne sont pas adjacents.
Draco18s
4
Cela [1, [[[2, 3]], [4], 5]]me ressemble .
Neil
Lequel (le cas échéant) de ces autres formats d'entrée serait acceptable?
13urous

Réponses:

12

Python 3 , 400 393 390 octets

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]

Renvoie une liste de chaînes de haut en bas.

EDIT 1: découpé 7 octets en évitant la duplication de ┴┼(sauvegarde nette de 2 octets), en supprimant 0 de la chaîne, en changeant la façon dont les caractères de dessin sont sélectionnés ┬┌┐(utilisez <au lieu de ==) et en remplaçant un L(z)manquant pare

EDIT 2: -2 octets grâce aux ovs et -1 octet grâce à Kevin Cruijssen

Essayez-le en ligne!

Non golfé

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]

Construit un arbre à partir des feuilles, une couche à la fois.

Beefster
la source
2
J'ai ajouté les cas de test à votre lien TIO Essayez-le en ligne!
pizzapants184
Bonne réponse! Vous pouvez raccourcir ce par deux octets en attribuant l'espace à une variable comme ceci: S,*K=' ┴┼│123456789'.
OVS
1
e==1peut être e<2de sauvegarder un octet (je ne pense pas qu'il puisse jamais être 0, car le défi indique que l'entrée n'est pas vide - et les entrées vides auraient déjà échoué à max(map(L,z))dans ce cas de toute façon.)
Kevin Cruijssen
3

Nettoyer , 544 506 octets

Les échappements sont utilisés pour éviter UTF-8 invalide sur SE / TIO mais comptés comme un octet car ils sont des littéraux valides

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

Essayez-le en ligne!

Prend entrée au format L[I 3, L[I 4, I 5], I 2]..

Relie les arbres de bas en haut, de gauche à droite, puis ajuste les distances de droite à gauche.

Prettifié, sorte de:

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]];
Οurous
la source
3

Fusain , 127 123 octets

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

Essayez-le en ligne! Le lien est vers la version détaillée du code. Explication:

Modifiez la direction de dessin par défaut vers le haut, car nous ne dessinons rien vers la droite.

≔⟦⟦θ⟧⟧η

La première étape consiste à convertir la représentation de tableau imbriqué dans une représentation d'index qui est une liste de toutes les entrées ainsi que les indices des sous - réseaux, par exemple pour l'entrée q=[1, [[[2, 3]], [4], 5]]du 5est q[1][2]et donc la liste que nous voulons est 1, 2. Nous commençons par une seule entrée à traiter qui est une liste contenant une liste des indices actuels (c'est-à-dire aucun jusqu'à présent) et l'entrée d'origine.

Fη«

Faites une boucle sur les tableaux lorsque nous les traitons. (Idéalement, le charbon de bois continuera à parcourir une liste si vous appuyez dessus pendant l'itération.)

≔⊟ιζ

Obtenez le tableau suivant à traiter.

¿⁼Iζ⪫⟦ζ⟧ω

Est-ce en fait un scalaire plutôt qu'un tableau?

⊞υ⊞Oιζ

Si c'est le cas, alors la liste que nous avions appartient en fait à la liste finale des listes d'indices.

FLζ

Sinon, passez en boucle sur chaque élément de ce tableau ...

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

... et enregistrez-le avec sa nouvelle liste d'index jusqu'à présent pour un traitement ultérieur. L'index maximum du tableau est également enregistré, ce qui est utilisé pour caser le dernier élément du tableau.

Wυ«

Nous sommes maintenant prêts à parcourir la liste des listes d'index. Cependant, la liste n'est pas dans l'ordre lexicographique, nous ne pouvons donc pas l'itérer directement.

≔⌊υι

Trouvez l'élément suivant dans l'ordre lexicographique.

≔Φυ¬⁼κιυ

Retirez-le de la liste.

J±⊗Lυ⊘⊖Lι

Aller à la position du scalaire dans la sortie. Nous pouvons calculer cela étant donné que nous pouvons compter le nombre de scalaires que nous produisons et nous connaissons également le nombre d'entrées dans sa liste d'index.

I⊟ι

Imprimez en fait le scalaire.

Wι«

Faites une boucle sur les entrées de la liste d'index. Encore une fois, ce n'est pas une simple itération, car les entrées viennent par paires, et nous devons également pouvoir sortir de la boucle.

≔⊟ιζ

Extrayez le prochain index de la liste.

¿ζ«

Si ce n'est pas le premier élément de la liste ...

←§┐┬‹ζ⊟ι

... puis imprimez ou selon qu'il s'agit du dernier élément de la liste ...

W⁼KKψ←─

... et imprimez suffisamment de s pour remplir jusqu'à l'entrée précédente à ce niveau ...

≔⁰ι»

... et effacez la variable pour sortir de la boucle puisque nous avons terminé ici.

¿⊟ι┌¶┴

Sinon, s'il s'agit (du premier élément) d'une liste à plusieurs éléments, imprimez le ┌┴, en laissant le curseur au-dessus de pour traiter le parent de ce niveau.

¦│

Sinon, s'il s'agit d'une liste à 1 élément, il suffit d'imprimer un et de monter d'une ligne pour traiter avec le parent de ce niveau.

Neil
la source