配列からツリーを描く


24

1桁の正の整数の入れ子になっている可能性のある空でない配列(一意であることが保証されていない)を指定すると、ボックス描画文字を使用してASCIIアート表現をツリーとして出力します┌ ┴ ┐ ─ │ ┬ ┼。(これらはコードページ437からコピーされましたが、同等の表現を使用できます)。

配列のすべての整数は、ツリーの葉でなければなりません。配列の同じレベルの要素は、ツリーの同じレベルに存在する必要があります。すべての要素は、明確に区別できるように十分な空白で区切る必要があります(1つのスペースの最小幅を決定するのはユーザー次第です)。

たとえば、与えられた配列[[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]]私のように見えます。
ニール

これらの代替入力形式のどれが(もしあれば)受け入れられますか?
02

回答:


12

Pythonの3400の 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バイト┴┼方法描画文字を、1つの文字列から0を切り出し、(2バイトの保存ネット)を変更は、以下から選択される┬┌┐(使用<の代わりに==)と交換L(z)私は逃しe

編集2:ovsのおかげで-2バイト、Kevin Cruijssenのおかげで-1バイト

オンラインでお試しください!

非ゴルフ

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]

一度に1層ずつ、葉から木を構築します。


2
TIOリンクにテストケースを追加しましたオンラインで試してみてください!
pizzapants184

いい答えだ!次のようにスペースを変数に割り当てることにより、これを2バイト短縮できますS,*K=' ┴┼│123456789'
ovs

1
e==1ことができますe<2(私は挑戦が入力が非空で述べているので、それは今までに0することができないと思う-と空の入力はすでにで失敗しただろうバイトを保存するmax(map(L,z))。とにかくその場合の)
ケビンCruijssen

3

クリーン544 506バイト

SE / TIOで無効なUTF-8を回避するためにエスケープが使用されますが、有効なリテラルであるため1バイトとしてカウントされます

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]]の場合5はis q[1][2]なので、必要なリストはです1, 2。現在のインデックスのリスト(つまり、これまでにないもの)と元の入力を含むリストである、処理する単一のエントリから始めます。

Fη«

配列をループ処理します。(便利なことに、イテレーション中にプッシュすると、Charcoalはリストのイテレーションを続行します。)

≔⊟ιζ

処理する次の配列を取得します。

¿⁼Iζ⪫⟦ζ⟧ω

これは実際には配列ではなくスカラーですか?

⊞υ⊞Oιζ

もしそうなら、実際に私たちが持っていたリストは、インデックスのリストの最終リストに属します。

FLζ

それ以外の場合は、この配列の各要素をループします...

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

...そして、これを新しいインデックスリストで保存して、さらに処理します。配列の最後の要素を特別な場合に使用する配列の最大インデックスも保存されます。

Wυ«

これで、インデックスリストのリストをループする準備ができました。ただし、リストは辞書式順序ではないため、直接反復することはできません。

≔⌊υι

辞書順で次の要素を見つけます。

≔Φυ¬⁼κιυ

リストから削除します。

J±⊗Lυ⊘⊖Lι

出力内のスカラーの位置にジャンプします。出力されたスカラーの数のカウントを保持でき、インデックスリスト内のエントリの数もわかっている場合、これを計算できます。

I⊟ι

実際にスカラーを出力します。

Wι«

インデックスリストのエントリをループします。繰り返しになりますが、これは単純な反復ではありません。エントリがペアになっており、ループから抜け出す必要があるためです。

≔⊟ιζ

リストから次のインデックスを抽出します。

¿ζ«

これがリストの最初の要素でない場合...

←§┐┬‹ζ⊟ι

...その後、印刷したり、これはリストの最後の要素であるかどうかに応じて...

W⁼KKψ←─

...そして、このレベルの前のエントリまで入力するのに十分なsを印刷します...

≔⁰ι»

...そして、ここで完了したので、ループから抜け出すために変数をクリアします。

¿⊟ι┌¶┴

それ以外の場合、これが複数要素リスト(の最初の要素)である場合、を印刷し┌┴、カーソルを上に残してこのレベルの親を処理します。

¦│

それ以外の場合、これが1要素のリストである場合は、a を出力し、このレベルの親を処理するために1行上に移動します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.