Складіть алфавітТрі


31

Розглянемо наступний алфавітно відсортований список слів:

balderdash
ballet
balloonfish
balloonist
ballot
brooding
broom

Усі слова починаються з b, а перші 5 починаються з bal. Якщо ми просто подивимось на перші 2 слова:

balderdash
ballet

ми могли б замість цього написати:

balderdash
  +let

де ' 'використовується, коли слово поділяє символ префікса з попереднім словом; за винятком '+'символу, який позначає ОСТАННІЙ символ, де друге слово розділяє префікс з попереднім словом.

Це своєрідна візуалізація «трійки» : батьків є ' bal', і має 2 нащадки: 'derdash'і 'let'.

З більш довгим списком, наприклад:

balderdash
ballet
brooding

ми можемо додатково використати символ труби, '|'щоб зрозуміти, де закінчується спільний префікс:

balderdash
| +let
+rooding

і еквівалентну дерево матиме корінь , 'b'який має двох дітей: в поддереве , що має корінь 'al'і та її двоє дітей , 'derdash'і 'let'; і 'rooding'.

Якщо ми застосуємо цю стратегію до нашого початкового списку,

balderdash
ballet
balloonfish
balloonist
ballot
brooding
broom

ми отримуємо вихід, який виглядає так:

balderdash    
| +let     
|  +oonfish
|   | +ist 
|   +t     
+rooding   
   +m 

Якщо два послідовних слова у списку не мають спільного префіксу, не замінюються спеціальні символи; наприклад для списку:

broom
brood
crude
crumb

ми хочемо вихід:

broom
   +d
crude
  +mb

Вхідні дані

Слова у введенні будуть складатися лише з буквено-цифрових знаків (без пробілів і пунктуації); це може бути у вигляді списку рядків, окремої рядки або будь-якого іншого розумного підходу, якщо ви вкажете вибраний формат. Жодні два слова поспіль не будуть однаковими. Список буде відсортований за алфавітом.

Вихід

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

Це ; найкоротший код на кожній мові зберігає права на хвастощі. Діють звичайні заборони проти лазівки.

Випробування

Input:
apogee
apology
app
apple
applique
apply
apt

Output:
apogee     
 |+logy    
 +p        
 |+le      
 | +ique   
 | +y      
 +t        

Input:
balderdash
ballet
balloonfish
balloonist
ballot
brooding
broom
donald
donatella
donna
dont
dumb

Output:
balderdash 
| +let     
|  +oonfish
|   | +ist 
|   +t     
+rooding   
   +m      
donald     
| |+tella  
| +na      
| +t       
+umb 

Як щодо випадку, коли я маю слово ballпісля balloon. Якого результату слід очікувати?
Дон Тисяча

@RushabhMehta Я здогадуюсь, у вас би було просто +перше o, але я не написав виклик, тому я не впевнений.
Тео

5
@RushabhMehta Слова впорядковані за алфавітом, тому цього не станеться.
Ніл

@Neil О хороший момент
Дон Тисяча

2
Слова у введенні будуть складатися лише з буквено-цифрових значень : чи дійсно це включає цифри, чи ви мали на увазі буквене значення?
Арнольд

Відповіді:


11

Сітківка 0,8,2 , 58 57 байт

^((.*).)(?<=\b\1.*¶\1)
$.2$* +
m)+`^(.*) (.*¶\1[+|])
$1|$2

Спробуйте в Інтернеті! Посилання включає в себе один тестовий випадок. Редагувати: Збережено 1 байт завдяки @FryAmTheEggman вказуючи на те, що я не помітив переходу з \bна, що ^стало можливим m). Пояснення:

m)

Увімкніть на рядку ^всю програму.

^((.*).)(?<=^\1.*¶\1)
$.2$* +

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

+`^(.*) (.*¶\1[+|])
$1|$2

Неодноразово замінюйте всі проміжки безпосередньо над +s або |s на |s.


@FryAmTheEggman Дійсно, я додав m)спеціально, щоб мати змогу це зробити, тому мені прикро, що я пропустив екземпляр.
Ніл

Тьфу, чому я навіть не можу відповідати на коментарі, якщо люди просто збираються їх видалити ...
Ніл

9

JavaScript (ES6), 128 байт

Очікує і повертає список списків символів.

a=>a.map((w,y)=>a[~y]=w.map(m=(c,x)=>(p=a[y-1]||0,m|=c!=p[x])?c:p[x+1]==w[x+1]?' ':(g=y=>a[y][x]<1?g(y+1,a[y][x]='|'):'+')(-y)))

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

Як?

Пробіли та +s можуть бути вставлені шляхом проходження по першому та останньому слову по порядку, але |їх можна вставити лише після того, як a +буде визначено a . Цього можна досягти, зробивши два пропуски, але натомість ми зберігаємо вказівник на кожну модифіковану запис, a[~y]щоб згодом її знову можна було оновити в межах одного map()циклу.

Теоретично, більш простим рішенням буде проходження слів у зворотному порядку та повернення результатів, а також в кінці процесу. Але це в JS трохи дорого, і я не знайшов способу отримати скорочену версію за допомогою цього методу.

a =>                           // a[] = input array
  a.map((w, y) =>              // for each word w at position y in a[]:
    a[~y] =                    //   save a pointer to the current entry in a[~y]
    w.map(m =                  //   initialize m to a non-numeric value
      (c, x) => (              //   for each character c at position x in w:
        p = a[y - 1] || 0,     //     p = previous word or a dummy object
        m |= c != p[x]         //     set m = 1 as soon as w differs from p at this position
      ) ?                      //     if w is no longer equal to p:
        c                      //       append c
      :                        //     else:
        p[x + 1] == w[x + 1] ? //       if the next characters are still matching:
          ' '                  //         append a space
        : (                    //       else:
            g = y =>           //         g() = recursive function to insert pipes
            a[y][x] < 1 ?      //           if a[y][x] is a space:
              g(               //             do a recursive call to g()
                y + 1,         //               with y + 1
                a[y][x] = '|'  //               and overwrite a[y][x] with a pipe
              )                //             end of recursive call
            :                  //           else:
              '+'              //             make the whole recursion chain return a '+'
                               //             which will be appended in the current entry
          )(-y)                //         initial call to g() with -y (this is ~y + 1)
    )                          //   end of map() over the characters
  )                            // end of map() over the words

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

@DanielIndie Не хвилюйся. Досить різна.
Арнольд


1

Пітон, 263 260 байт

- 3 байти завдяки Джонатану Фреху

Код:

p=lambda t,f,g:"\n".join([(f[:-1]+"+"if(a!=min(t))*g else"")+a+p(t[a],(f+" "if len(t[a])>1or a==max(t)else f[:-1]+"| "),1)for a in t])if t else""
def a(t,x):
 if x:c=x[0];t[c]=c in t and t[c]or{};a(t[c],x[1:])
def f(*s):t={};[a(t,i)for i in s];return p(t,"",0)

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

Пояснення:

Це рішення створює трійник із введених слів і рекурсивно аналізує його на необхідний вихід. Функція приймає трійку t і рядок s і додає х до t. Спроби реалізовані у вигляді вкладених словників. Кожен словник являє собою вузол у трійці. Наприклад, словник, що представляє трійник, сформований у першому тестовому випадку, виглядає так:

{'b': {'a': {'l': {'d': {'e': {'r': {'d': {'a': {'s': {'h': {}}}}}}}, 'l': {'e': {'t': {}}, 'o': {'o': {'n': {'f': {'i': {'s': {'h': {}}}}, 'i': {'s': {'t': {}}}}}, 't': {}}}}}, 'r': {'o': {'o': {'d': {'i': {'n': {'g': {}}}}, 'm': {}}}}}}

Функція p повторюється через цю структуру і генерує рядкове представлення трійки, очікуваного викликом. Функція f бере купу аргументів як аргументи, додає їх до трійки з а, потім повертає результат виклику p на трійці.



1

C (gcc) , 165 155 байт

Бере три аргументи:

  • char** a : масив слів, що закінчуються нулем
  • char* m : масив довжини кожного слова
  • int n : кількість слів у масиві
f(a,m,n,i,j)char**a,*m;{for(i=n;--i;)for(j=0;j<m[i]&j<m[i-1]&a[i][j]==a[i-1][j];j++)a[i][j]=a[i][j+1]^a[i-1][j+1]?43:++i<n&j<m[i]&a[i--][j]%81==43?124:32;}

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



@Arnauld Звичайно! Хоча це не ++i<n&j<m[i]&a[i--]визначена поведінка? Чи можу я покластися на те, що gcc оцінює його зліва направо?
Кертіс Бехтел

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

1

Perl 6 , 149 144 142 байт

{1 while s/(\n.*)\s(.*)$0(\+|\|)/$0|$1$0$2/;$_}o{$=({.[1].subst(/^(.+)<?{.[0].index($0)eq 0}>/,{' 'x$0.ords-1~'+'})}for '',|$_ Z$_).join("
")}

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

Я впевнений, що це може бути більше гольфу, тим більше, що я не фахівець з регексів. Для цього використовується майже той самий процес, що і відповідь Нітла на сітківку .



0

Рубін , 118 байт

->a{i=1;a.map{s="";a[i+=j=-1].chars{|c|a[i][j+=1]=i<0&&a[i-1][/^#{s+=c}/]?a[i+1][j]=~/[|+]/??|:?\s:c}[/[| ]\b/]&&=?+}}

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

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

Пояснення

Перетворення базових рядків не надто складне, але для того, щоб вставити вертикальні труби належним чином, нам потрібно повторити в зворотному порядку, а оскільки reverseметод є досить багатослівним, ми зробимо це складніше. Тут ми використовуємо mapпросто для запуску циклу, залиште перше слово в спокої, а потім повторіть з кінця за допомогою негативних показників:

->a{
 i=1;                   #Initialize word indexer
 a.map{                 #Loop
  s="";                 #Initialize lookup string
  a[i+=j=-1]            #Initialize char indexer and decrement i
  .chars{|c|            #Loop through each char c of current word
   a[i][j+=1]=          #Mofify current word at position j 
    i<0&&               #If it's not the first word and
    a[i-1][/^#{s+=c}/]? #Word above matches current one from start to j
     a[i+1][j]=~/[|+]/? #Then if char below is | or +
      ?|:?\s:c          #Then set current char to | Else to Space Else leave as is
  }[/[| ]\b/]&&=?+      #Finally, replace Space or | at word boundary with +
 }
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.