Малювання дерева з масиву


24

З огляду на можливо вкладений, не порожній масив одноцифрових додатних цілих чисел (не гарантовано унікальних), виведіть ASCII-художнє представлення у вигляді дерева, використовуючи символи вікна, що малюють ┌ ┴ ┐ ─ │ ┬ ┼. (Вони були скопійовані з коду сторінки 437, але ви можете використовувати будь-яке еквівалентне представлення).

Кожне ціле число масиву має бути листям дерева. Елементи одного рівня глибоко в масиві повинні бути присутніми на одному рівні дерева. Усі елементи повинні бути розділені достатньою кількістю пробілів, щоб їх було чітко (залежно від вас, щоб визначити, якою шириною буде мінімум один пробіл між ними).

Наприклад, заданий масив [[1, [2]], [3, [4, 5]]]вивести наступне дерево

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

Для масиву [1, 2, 3]може виглядати дерево

┌─┼─┐
1 2 3

Але масив [[1, 2, 3]]виглядав би так

  │
┌─┼─┐
1 2 3

Тоді як масив [1, [1, [1, [1]]]]міг виглядати

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

Як складніший приклад [1, [[[2, 3], 4], 5]]може бути

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

або кілька інших варіацій.


  • Введення та вихід можуть бути надані будь-яким зручним методом .
  • Ви можете роздрукувати його до STDOUT або повернути його як результат функції.
  • Прийнятна або повна програма, або функція.
  • Будь-яка кількість сторонніх пробілів є прийнятною, доки символи не належним чином розташовуються.
  • Стандартні лазівки заборонені.
  • Це тому діють усі звичайні правила гольфу, і найкоротший код (у байтах) виграє.

[1,[[[2,3],4],5]]може бути цікавим тестовим випадком, оскільки він повинен мати корінь штучно розширений, щоб праве піддерево не стикалося з лівим піддеревом.
Піка

@Poke Додано як приклад. Для цього тестового випадку існує кілька можливих варіантів.
AdmBorkBork

2
Перший приклад для цього тестового випадку не може бути правильним. Це говорить про те, що другий за елементу поруч з 1являє собою масив з 3 -х елементів: [2,3], 4, і 5. Але 4 і 5 не є суміжними.
Draco18s

4
Це [1, [[[2, 3]], [4], 5]]мені схоже .
Ніл

Який (якщо такий є) із цих альтернативних форматів введення був би прийнятний?
Οurous

Відповіді:


12

Python 3 , 400 393 390 байт

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]

Повертає список рядків зверху вниз.

EDIT 1: Обрізано 7 байтів, уникаючи дублювання ┴┼(чистого збереження 2 байтів), вирізаючи 0 з однієї рядка, змінюючи спосіб вибору символів малювання ┬┌┐(використовувати <замість ==), і замінюючи L(z)пропущений яe

EDIT 2: -2 байти завдяки ovs і -1 байт завдяки Kevin Cruijssen

Спробуйте в Інтернеті!

Безумовно

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]

Будує дерево з листя вгору, по одному шару.


2
Я додав тестові кейси до вашої посилання TIO. Спробуйте в Інтернеті!
pizzapants184

Гарна відповідь! Ви можете скоротити це два байта, призначаючи місце для змінної , як це: S,*K=' ┴┼│123456789'.
ов

1
e==1можна e<2зберегти байт (я не думаю, що це коли-небудь може бути 0, оскільки виклик констатує, що вхід не порожній - і порожні входи max(map(L,z))в цьому випадку вже не змогли б ).
Кевін Кройсейсен

3

Чисто , 544 506 байт

Ескапаси використовуються для уникнення недійсних UTF-8 на SE / TIO, але рахуються як один байт, оскільки вони є дійсними літералами

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

Спробуйте в Інтернеті!

Здійснює введення у форматі L[I 3, L[I 4, I 5], I 2]..

З’єднує дерева знизу вгору, зліва направо, потім коригує відстані справа наліво.

Досконалий, сортування:

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

Деревне вугілля , 127 123 байт

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

Спробуйте в Інтернеті! Посилання на багатослівну версію коду. Пояснення:

Змініть за замовчуванням напрямок малювання вгору, оскільки ми нічого не намалюємо праворуч.

≔⟦⟦θ⟧⟧η

Перший крок полягає в перетворенні вкладеного уявлення масиву в уявлення індексу , який є списком всіх записів разом з індексами подмассивов, наприклад , для введення є і , отже , в списку ми хочемо . Ми починаємо з одного запису, який обробляється списком, що містить перелік поточних індексів (тобто жодного поки що немає) та оригінального введення.q=[1, [[[2, 3]], [4], 5]]5q[1][2]1, 2

Fη«

Проводимо петлю над масивами під час їх обробки. (Зручно, що деревне вугілля продовжуватиме повторювати список, якщо ви натискаєте на нього під час ітерації.)

≔⊟ιζ

Отримайте наступний масив для обробки.

¿⁼Iζ⪫⟦ζ⟧ω

Це насправді скаляр, а не масив?

⊞υ⊞Oιζ

Якщо так, то список, який ми мали, насправді належить до остаточного списку списків індексів.

FLζ

В іншому випадку переведіть цикл на кожен елемент цього масиву ...

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

... і збережіть його з новим покажчиком поки що для подальшої обробки. Також зберігається максимальний індекс масиву, який використовується для особливого випадку останнього елемента масиву.

Wυ«

Зараз ми готові переглядати список списків індексів. Однак список не в лексикографічному порядку, тому ми не можемо його повторити безпосередньо.

≔⌊υι

Знайдіть наступний елемент у лексикографічному порядку.

≔Φυ¬⁼κιυ

Видаліть його зі списку.

J±⊗Lυ⊘⊖Lι

Перейти до положення скаляра на виході. Ми можемо обчислити це, враховуючи, що ми можемо вести підрахунок кількості виданих скалярів, а також знаємо кількість записів у його списку індексів.

I⊟ι

Насправді надрукуйте скаляр.

Wι«

Проведіть петлю над записами у списку індексів. Знову ж таки, це не проста ітерація, оскільки записи надходять парами, і нам також потрібно мати можливість вийти з циклу.

≔⊟ιζ

Витягніть наступний індекс зі списку.

¿ζ«

Якщо це не перший елемент у списку ...

←§┐┬‹ζ⊟ι

... потім надрукуйте або залежно від того, чи є останнім елементом у списку ...

W⁼KKψ←─

... і надрукувати достатньо s, щоб заповнити попередній запис на цьому рівні ...

≔⁰ι»

... і очистити змінну, щоб вирватися з циклу, оскільки ми закінчили тут.

¿⊟ι┌¶┴

В іншому випадку, якщо це (перший елемент) списку з декількома елементами, тоді надрукуйте ┌┴, залишивши курсор вище значення для обробки з батьківським рівнем цього рівня.

¦│

В іншому випадку, якщо це 1-елементний список, тоді просто надрукуйте "a" та перемістіть вгору рядок, щоб мати справу з батьківським рівнем цього рівня.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.