Make an alphabeTrie

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP











up vote
29
down vote

favorite
1












Consider the following alphabetically sorted list of words:



balderdash
ballet
balloonfish
balloonist
ballot
brooding
broom


All of the words start with b, and the first 5 start with bal. If we just look at the first 2 words:



balderdash
ballet


we could write instead:



balderdash
+let


where the ' ' is used where a word shares a prefix character with the previous word; except for the '+' character which indicates the LAST character where the second word shares a prefix with the previous word.



This is a sort of 'trie' visualization: the parent is 'bal', and has 2 descendants: 'derdash' and 'let'.



With a longer list, such as:



balderdash
ballet
brooding


we can additionally use the pipe character '|' to make it clearer where the shared prefix ends, as follows:



balderdash
| +let
+rooding


and the equivalent tree would have a root of 'b' having two children: the subtree having root 'al' and and its two children 'derdash' and 'let'; and 'rooding'.



If we apply this strategy to our original list,



balderdash
ballet
balloonfish
balloonist
ballot
brooding
broom


we get output that looks like:



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


If two consecutive words in the list have no shared prefix, no special characters are substituted; e.g. for the list:



broom
brood
crude
crumb


we want the output:



broom
+d
crude
+mb


Input



The words in the input will be made up of only alphanumerics (no spaces or punctuation); this may be in the form of a list of strings, a single string, or any other reasonable approach, as long as you specify your chosen format. No two consecutive words will be the same. The list will be alphabetically sorted.



Output



Your output can contain trailing whitespace per line or in total, but no leading whitespace. A list of strings or similar would also be acceptable.



This is code-golf; the shortest code in each language retains bragging rights. The usual prohibitions against loopholes apply.



Test Cases



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






share|improve this question






















  • What about the case where I have the word ball after balloon. What output should we expect?
    – Rushabh Mehta
    Aug 13 at 20:05










  • @RushabhMehta I'm guessing you would just have a + under the first o, but I didn't write the challenge so I'm not certain.
    – Theo
    Aug 13 at 20:12







  • 5




    @RushabhMehta The words are alphabetically sorted, so this won't happen.
    – Neil
    Aug 13 at 20:14










  • @Neil Oh good point
    – Rushabh Mehta
    Aug 13 at 20:18






  • 2




    The words in the input will be made up of only alphanumerics: does that really include digits, or did you mean alphabetic?
    – Arnauld
    Aug 14 at 1:40














up vote
29
down vote

favorite
1












Consider the following alphabetically sorted list of words:



balderdash
ballet
balloonfish
balloonist
ballot
brooding
broom


All of the words start with b, and the first 5 start with bal. If we just look at the first 2 words:



balderdash
ballet


we could write instead:



balderdash
+let


where the ' ' is used where a word shares a prefix character with the previous word; except for the '+' character which indicates the LAST character where the second word shares a prefix with the previous word.



This is a sort of 'trie' visualization: the parent is 'bal', and has 2 descendants: 'derdash' and 'let'.



With a longer list, such as:



balderdash
ballet
brooding


we can additionally use the pipe character '|' to make it clearer where the shared prefix ends, as follows:



balderdash
| +let
+rooding


and the equivalent tree would have a root of 'b' having two children: the subtree having root 'al' and and its two children 'derdash' and 'let'; and 'rooding'.



If we apply this strategy to our original list,



balderdash
ballet
balloonfish
balloonist
ballot
brooding
broom


we get output that looks like:



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


If two consecutive words in the list have no shared prefix, no special characters are substituted; e.g. for the list:



broom
brood
crude
crumb


we want the output:



broom
+d
crude
+mb


Input



The words in the input will be made up of only alphanumerics (no spaces or punctuation); this may be in the form of a list of strings, a single string, or any other reasonable approach, as long as you specify your chosen format. No two consecutive words will be the same. The list will be alphabetically sorted.



Output



Your output can contain trailing whitespace per line or in total, but no leading whitespace. A list of strings or similar would also be acceptable.



This is code-golf; the shortest code in each language retains bragging rights. The usual prohibitions against loopholes apply.



Test Cases



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






share|improve this question






















  • What about the case where I have the word ball after balloon. What output should we expect?
    – Rushabh Mehta
    Aug 13 at 20:05










  • @RushabhMehta I'm guessing you would just have a + under the first o, but I didn't write the challenge so I'm not certain.
    – Theo
    Aug 13 at 20:12







  • 5




    @RushabhMehta The words are alphabetically sorted, so this won't happen.
    – Neil
    Aug 13 at 20:14










  • @Neil Oh good point
    – Rushabh Mehta
    Aug 13 at 20:18






  • 2




    The words in the input will be made up of only alphanumerics: does that really include digits, or did you mean alphabetic?
    – Arnauld
    Aug 14 at 1:40












up vote
29
down vote

favorite
1









up vote
29
down vote

favorite
1






1





Consider the following alphabetically sorted list of words:



balderdash
ballet
balloonfish
balloonist
ballot
brooding
broom


All of the words start with b, and the first 5 start with bal. If we just look at the first 2 words:



balderdash
ballet


we could write instead:



balderdash
+let


where the ' ' is used where a word shares a prefix character with the previous word; except for the '+' character which indicates the LAST character where the second word shares a prefix with the previous word.



This is a sort of 'trie' visualization: the parent is 'bal', and has 2 descendants: 'derdash' and 'let'.



With a longer list, such as:



balderdash
ballet
brooding


we can additionally use the pipe character '|' to make it clearer where the shared prefix ends, as follows:



balderdash
| +let
+rooding


and the equivalent tree would have a root of 'b' having two children: the subtree having root 'al' and and its two children 'derdash' and 'let'; and 'rooding'.



If we apply this strategy to our original list,



balderdash
ballet
balloonfish
balloonist
ballot
brooding
broom


we get output that looks like:



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


If two consecutive words in the list have no shared prefix, no special characters are substituted; e.g. for the list:



broom
brood
crude
crumb


we want the output:



broom
+d
crude
+mb


Input



The words in the input will be made up of only alphanumerics (no spaces or punctuation); this may be in the form of a list of strings, a single string, or any other reasonable approach, as long as you specify your chosen format. No two consecutive words will be the same. The list will be alphabetically sorted.



Output



Your output can contain trailing whitespace per line or in total, but no leading whitespace. A list of strings or similar would also be acceptable.



This is code-golf; the shortest code in each language retains bragging rights. The usual prohibitions against loopholes apply.



Test Cases



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






share|improve this question














Consider the following alphabetically sorted list of words:



balderdash
ballet
balloonfish
balloonist
ballot
brooding
broom


All of the words start with b, and the first 5 start with bal. If we just look at the first 2 words:



balderdash
ballet


we could write instead:



balderdash
+let


where the ' ' is used where a word shares a prefix character with the previous word; except for the '+' character which indicates the LAST character where the second word shares a prefix with the previous word.



This is a sort of 'trie' visualization: the parent is 'bal', and has 2 descendants: 'derdash' and 'let'.



With a longer list, such as:



balderdash
ballet
brooding


we can additionally use the pipe character '|' to make it clearer where the shared prefix ends, as follows:



balderdash
| +let
+rooding


and the equivalent tree would have a root of 'b' having two children: the subtree having root 'al' and and its two children 'derdash' and 'let'; and 'rooding'.



If we apply this strategy to our original list,



balderdash
ballet
balloonfish
balloonist
ballot
brooding
broom


we get output that looks like:



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


If two consecutive words in the list have no shared prefix, no special characters are substituted; e.g. for the list:



broom
brood
crude
crumb


we want the output:



broom
+d
crude
+mb


Input



The words in the input will be made up of only alphanumerics (no spaces or punctuation); this may be in the form of a list of strings, a single string, or any other reasonable approach, as long as you specify your chosen format. No two consecutive words will be the same. The list will be alphabetically sorted.



Output



Your output can contain trailing whitespace per line or in total, but no leading whitespace. A list of strings or similar would also be acceptable.



This is code-golf; the shortest code in each language retains bragging rights. The usual prohibitions against loopholes apply.



Test Cases



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








share|improve this question













share|improve this question




share|improve this question








edited Aug 13 at 19:30









Mr. Xcoder

30.1k757193




30.1k757193










asked Aug 13 at 19:12









Chas Brown

4,1361319




4,1361319











  • What about the case where I have the word ball after balloon. What output should we expect?
    – Rushabh Mehta
    Aug 13 at 20:05










  • @RushabhMehta I'm guessing you would just have a + under the first o, but I didn't write the challenge so I'm not certain.
    – Theo
    Aug 13 at 20:12







  • 5




    @RushabhMehta The words are alphabetically sorted, so this won't happen.
    – Neil
    Aug 13 at 20:14










  • @Neil Oh good point
    – Rushabh Mehta
    Aug 13 at 20:18






  • 2




    The words in the input will be made up of only alphanumerics: does that really include digits, or did you mean alphabetic?
    – Arnauld
    Aug 14 at 1:40
















  • What about the case where I have the word ball after balloon. What output should we expect?
    – Rushabh Mehta
    Aug 13 at 20:05










  • @RushabhMehta I'm guessing you would just have a + under the first o, but I didn't write the challenge so I'm not certain.
    – Theo
    Aug 13 at 20:12







  • 5




    @RushabhMehta The words are alphabetically sorted, so this won't happen.
    – Neil
    Aug 13 at 20:14










  • @Neil Oh good point
    – Rushabh Mehta
    Aug 13 at 20:18






  • 2




    The words in the input will be made up of only alphanumerics: does that really include digits, or did you mean alphabetic?
    – Arnauld
    Aug 14 at 1:40















What about the case where I have the word ball after balloon. What output should we expect?
– Rushabh Mehta
Aug 13 at 20:05




What about the case where I have the word ball after balloon. What output should we expect?
– Rushabh Mehta
Aug 13 at 20:05












@RushabhMehta I'm guessing you would just have a + under the first o, but I didn't write the challenge so I'm not certain.
– Theo
Aug 13 at 20:12





@RushabhMehta I'm guessing you would just have a + under the first o, but I didn't write the challenge so I'm not certain.
– Theo
Aug 13 at 20:12





5




5




@RushabhMehta The words are alphabetically sorted, so this won't happen.
– Neil
Aug 13 at 20:14




@RushabhMehta The words are alphabetically sorted, so this won't happen.
– Neil
Aug 13 at 20:14












@Neil Oh good point
– Rushabh Mehta
Aug 13 at 20:18




@Neil Oh good point
– Rushabh Mehta
Aug 13 at 20:18




2




2




The words in the input will be made up of only alphanumerics: does that really include digits, or did you mean alphabetic?
– Arnauld
Aug 14 at 1:40




The words in the input will be made up of only alphanumerics: does that really include digits, or did you mean alphabetic?
– Arnauld
Aug 14 at 1:40










8 Answers
8






active

oldest

votes

















up vote
11
down vote














Retina 0.8.2, 58 57 bytes



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


Try it online! Link includes one test case. Edit: Saved 1 byte thanks to @FryAmTheEggman pointing out that I overlooked a switch from b to ^ made possible by the m). Explanation:



m)


Turn on per-line ^ for the whole program.



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


For each word, try to match as much as possible from the beginning of the previous word. Change the match to spaces, except the last character, which becomes a +.



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


Repeatedly replace all spaces immediately above +s or |s with |s.






share|improve this answer






















  • @FryAmTheEggman Indeed, I added the m) specifically to be able to do that, so I'm annoyed that I missed an instance.
    – Neil
    Aug 15 at 23:41










  • Ugh, why do I even bother replying to comments if people are just going to delete them...
    – Neil
    Aug 16 at 8:30

















up vote
9
down vote













JavaScript (ES6), 128 bytes



Expects and returns a list of lists of characters.





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)))


Try it online!



How?



Spaces and +'s can be inserted by walking through the first to the last word in order, but |'s can only be inserted a posteriori once a + has been identified. This could be achieved by doing two distinct passes, but instead we save a pointer to each modified entry in a[~y] so that it can later be updated again within the same map() loop.



In theory, a simpler workaround would be to walk through the words in reverse order and to reverse the output as well at the end of the process. But this is a bit costly in JS and I didn't find a way to get a shorter version with this method.



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





share|improve this answer






















  • would you look at my solution, i came up with it myself but it reminds of your solution. so if its too close you can submit it as yours (or not) and ill delete it :)
    – DanielIndie
    Aug 17 at 16:22










  • @DanielIndie No worries. It's different enough.
    – Arnauld
    Aug 20 at 11:00

















up vote
2
down vote














JavaScript (Node.js), 125 122 118 117 bytes





a=>a.map((w,i)=>a[i]=w.map((T,k)=>+i&&l[k]==T?l[-~k]<w[-~k]?(g=_=>a[--i][k]<"+"?g(a[i][k]="|"):"+")():" ":(i=l=w,T)))


Try it online!



  • thanks to @Arnauld for tio testing :)





share|improve this answer





























    up vote
    1
    down vote













    Python, 263 260 bytes



    -3 bytes thanks to Jonathan Frech



    Code:



    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)


    Try it Online!



    Explanation:



    This solution builds a trie out of the input words and recursively parses it into the required output. The a function takes a trie t and a string s and adds x to t. Tries are implemented as nested dictionaries. Each dictionary represents a node in the trie. For example, the dictionary representing the trie generated by the first test case looks like this:



    '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': 


    The p function recurses through this structure and generates the string representation of the trie expected by the challenge. The f function takes a bunch of strings as arguments, adds them all to a trie with a, then returns the result of calling p on the trie.






    share|improve this answer


















    • 1




      Possible 252 bytes.
      – Jonathan Frech
      Aug 14 at 2:23

















    up vote
    1
    down vote














    C (gcc), 165 155 bytes



    Takes three arguments:




    • char** a : an array of null-terminated words


    • char* m : an array of the length of each word


    • int n : the number of words in the array

    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;


    Try it online!






    share|improve this answer


















    • 1




      Some quick wins
      – Arnauld
      Aug 14 at 10:08










    • @Arnauld Of course! Although isn't ++i<n&j<m[i]&a[i--] undefined behavior? Can I rely on gcc evaluating it left to right?
      – Curtis Bechtel
      Aug 14 at 13:31










    • It's very likely to be undefined behavior. But we define languages by their implementation, so as long as it works consistently with this version of gcc, I think that's fine.
      – Arnauld
      Aug 14 at 13:34

















    up vote
    1
    down vote














    Perl 6, 149 144 142 bytes





    1 while s/(n.*)s(.*)$0(+o$_ Z$_).join("
    ")


    Try it online!



    I'm sure this can be golfed a more, especially as I'm not an expert on regexes. This uses much the same process as Neil's Retina answer.






    share|improve this answer





























      up vote
      0
      down vote














      Python 2, 191 bytes





      def f(w,r=['']):
      for b,c in zip(w[1:],w)[::-1]:
      s='';d=0
      for x,y,z in zip(r[0]+b,b,c+b):t=s[-1:];s=s[:-1]+[['+'*(s>'')+y,t+' |'[x in'+|']][y==z],t+y][d];d=d|(y!=z)
      r=[s]+r
      return[w[0]]+r


      Try it online!






      share|improve this answer



























        up vote
        0
        down vote














        Ruby, 118 bytes





        ->ai=1;a.maps="";a[i+=j=-1].charsc[/[


        Try it online!



        Accepts an array of strings, outputs by modifying the original input array in-place.



        Explanation



        The basic string transformation is not too complex, but in order to insert vertical pipes properly, we need to iterate in reverse order, and since reverse method is quite verbose, we'll do it in a trickier way. Here, we use map just to run the loop, leave the first word alone, and then iterate from the end using negative indices:



        ->a
        i=1; #Initialize word indexer
        a.map at word boundary with +







        share|improve this answer






















          Your Answer




          StackExchange.ifUsing("editor", function ()
          return StackExchange.using("mathjaxEditing", function ()
          StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix)
          StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
          );
          );
          , "mathjax-editing");

          StackExchange.ifUsing("editor", function ()
          StackExchange.using("externalEditor", function ()
          StackExchange.using("snippets", function ()
          StackExchange.snippets.init();
          );
          );
          , "code-snippets");

          StackExchange.ready(function()
          var channelOptions =
          tags: "".split(" "),
          id: "200"
          ;
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function()
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled)
          StackExchange.using("snippets", function()
          createEditor();
          );

          else
          createEditor();

          );

          function createEditor()
          StackExchange.prepareEditor(
          heartbeatType: 'answer',
          convertImagesToLinks: false,
          noModals: false,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: null,
          bindNavPrevention: true,
          postfix: "",
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          );



          );













           

          draft saved


          draft discarded


















          StackExchange.ready(
          function ()
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodegolf.stackexchange.com%2fquestions%2f170580%2fmake-an-alphabetrie%23new-answer', 'question_page');

          );

          Post as a guest






























          8 Answers
          8






          active

          oldest

          votes








          8 Answers
          8






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes








          up vote
          11
          down vote














          Retina 0.8.2, 58 57 bytes



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


          Try it online! Link includes one test case. Edit: Saved 1 byte thanks to @FryAmTheEggman pointing out that I overlooked a switch from b to ^ made possible by the m). Explanation:



          m)


          Turn on per-line ^ for the whole program.



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


          For each word, try to match as much as possible from the beginning of the previous word. Change the match to spaces, except the last character, which becomes a +.



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


          Repeatedly replace all spaces immediately above +s or |s with |s.






          share|improve this answer






















          • @FryAmTheEggman Indeed, I added the m) specifically to be able to do that, so I'm annoyed that I missed an instance.
            – Neil
            Aug 15 at 23:41










          • Ugh, why do I even bother replying to comments if people are just going to delete them...
            – Neil
            Aug 16 at 8:30














          up vote
          11
          down vote














          Retina 0.8.2, 58 57 bytes



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


          Try it online! Link includes one test case. Edit: Saved 1 byte thanks to @FryAmTheEggman pointing out that I overlooked a switch from b to ^ made possible by the m). Explanation:



          m)


          Turn on per-line ^ for the whole program.



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


          For each word, try to match as much as possible from the beginning of the previous word. Change the match to spaces, except the last character, which becomes a +.



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


          Repeatedly replace all spaces immediately above +s or |s with |s.






          share|improve this answer






















          • @FryAmTheEggman Indeed, I added the m) specifically to be able to do that, so I'm annoyed that I missed an instance.
            – Neil
            Aug 15 at 23:41










          • Ugh, why do I even bother replying to comments if people are just going to delete them...
            – Neil
            Aug 16 at 8:30












          up vote
          11
          down vote










          up vote
          11
          down vote










          Retina 0.8.2, 58 57 bytes



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


          Try it online! Link includes one test case. Edit: Saved 1 byte thanks to @FryAmTheEggman pointing out that I overlooked a switch from b to ^ made possible by the m). Explanation:



          m)


          Turn on per-line ^ for the whole program.



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


          For each word, try to match as much as possible from the beginning of the previous word. Change the match to spaces, except the last character, which becomes a +.



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


          Repeatedly replace all spaces immediately above +s or |s with |s.






          share|improve this answer















          Retina 0.8.2, 58 57 bytes



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


          Try it online! Link includes one test case. Edit: Saved 1 byte thanks to @FryAmTheEggman pointing out that I overlooked a switch from b to ^ made possible by the m). Explanation:



          m)


          Turn on per-line ^ for the whole program.



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


          For each word, try to match as much as possible from the beginning of the previous word. Change the match to spaces, except the last character, which becomes a +.



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


          Repeatedly replace all spaces immediately above +s or |s with |s.







          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Aug 15 at 23:40

























          answered Aug 13 at 20:23









          Neil

          74.9k744170




          74.9k744170











          • @FryAmTheEggman Indeed, I added the m) specifically to be able to do that, so I'm annoyed that I missed an instance.
            – Neil
            Aug 15 at 23:41










          • Ugh, why do I even bother replying to comments if people are just going to delete them...
            – Neil
            Aug 16 at 8:30
















          • @FryAmTheEggman Indeed, I added the m) specifically to be able to do that, so I'm annoyed that I missed an instance.
            – Neil
            Aug 15 at 23:41










          • Ugh, why do I even bother replying to comments if people are just going to delete them...
            – Neil
            Aug 16 at 8:30















          @FryAmTheEggman Indeed, I added the m) specifically to be able to do that, so I'm annoyed that I missed an instance.
          – Neil
          Aug 15 at 23:41




          @FryAmTheEggman Indeed, I added the m) specifically to be able to do that, so I'm annoyed that I missed an instance.
          – Neil
          Aug 15 at 23:41












          Ugh, why do I even bother replying to comments if people are just going to delete them...
          – Neil
          Aug 16 at 8:30




          Ugh, why do I even bother replying to comments if people are just going to delete them...
          – Neil
          Aug 16 at 8:30










          up vote
          9
          down vote













          JavaScript (ES6), 128 bytes



          Expects and returns a list of lists of characters.





          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)))


          Try it online!



          How?



          Spaces and +'s can be inserted by walking through the first to the last word in order, but |'s can only be inserted a posteriori once a + has been identified. This could be achieved by doing two distinct passes, but instead we save a pointer to each modified entry in a[~y] so that it can later be updated again within the same map() loop.



          In theory, a simpler workaround would be to walk through the words in reverse order and to reverse the output as well at the end of the process. But this is a bit costly in JS and I didn't find a way to get a shorter version with this method.



          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





          share|improve this answer






















          • would you look at my solution, i came up with it myself but it reminds of your solution. so if its too close you can submit it as yours (or not) and ill delete it :)
            – DanielIndie
            Aug 17 at 16:22










          • @DanielIndie No worries. It's different enough.
            – Arnauld
            Aug 20 at 11:00














          up vote
          9
          down vote













          JavaScript (ES6), 128 bytes



          Expects and returns a list of lists of characters.





          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)))


          Try it online!



          How?



          Spaces and +'s can be inserted by walking through the first to the last word in order, but |'s can only be inserted a posteriori once a + has been identified. This could be achieved by doing two distinct passes, but instead we save a pointer to each modified entry in a[~y] so that it can later be updated again within the same map() loop.



          In theory, a simpler workaround would be to walk through the words in reverse order and to reverse the output as well at the end of the process. But this is a bit costly in JS and I didn't find a way to get a shorter version with this method.



          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





          share|improve this answer






















          • would you look at my solution, i came up with it myself but it reminds of your solution. so if its too close you can submit it as yours (or not) and ill delete it :)
            – DanielIndie
            Aug 17 at 16:22










          • @DanielIndie No worries. It's different enough.
            – Arnauld
            Aug 20 at 11:00












          up vote
          9
          down vote










          up vote
          9
          down vote









          JavaScript (ES6), 128 bytes



          Expects and returns a list of lists of characters.





          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)))


          Try it online!



          How?



          Spaces and +'s can be inserted by walking through the first to the last word in order, but |'s can only be inserted a posteriori once a + has been identified. This could be achieved by doing two distinct passes, but instead we save a pointer to each modified entry in a[~y] so that it can later be updated again within the same map() loop.



          In theory, a simpler workaround would be to walk through the words in reverse order and to reverse the output as well at the end of the process. But this is a bit costly in JS and I didn't find a way to get a shorter version with this method.



          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





          share|improve this answer














          JavaScript (ES6), 128 bytes



          Expects and returns a list of lists of characters.





          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)))


          Try it online!



          How?



          Spaces and +'s can be inserted by walking through the first to the last word in order, but |'s can only be inserted a posteriori once a + has been identified. This could be achieved by doing two distinct passes, but instead we save a pointer to each modified entry in a[~y] so that it can later be updated again within the same map() loop.



          In theory, a simpler workaround would be to walk through the words in reverse order and to reverse the output as well at the end of the process. But this is a bit costly in JS and I didn't find a way to get a shorter version with this method.



          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






          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Aug 14 at 13:50

























          answered Aug 14 at 2:06









          Arnauld

          63.3k580267




          63.3k580267











          • would you look at my solution, i came up with it myself but it reminds of your solution. so if its too close you can submit it as yours (or not) and ill delete it :)
            – DanielIndie
            Aug 17 at 16:22










          • @DanielIndie No worries. It's different enough.
            – Arnauld
            Aug 20 at 11:00
















          • would you look at my solution, i came up with it myself but it reminds of your solution. so if its too close you can submit it as yours (or not) and ill delete it :)
            – DanielIndie
            Aug 17 at 16:22










          • @DanielIndie No worries. It's different enough.
            – Arnauld
            Aug 20 at 11:00















          would you look at my solution, i came up with it myself but it reminds of your solution. so if its too close you can submit it as yours (or not) and ill delete it :)
          – DanielIndie
          Aug 17 at 16:22




          would you look at my solution, i came up with it myself but it reminds of your solution. so if its too close you can submit it as yours (or not) and ill delete it :)
          – DanielIndie
          Aug 17 at 16:22












          @DanielIndie No worries. It's different enough.
          – Arnauld
          Aug 20 at 11:00




          @DanielIndie No worries. It's different enough.
          – Arnauld
          Aug 20 at 11:00










          up vote
          2
          down vote














          JavaScript (Node.js), 125 122 118 117 bytes





          a=>a.map((w,i)=>a[i]=w.map((T,k)=>+i&&l[k]==T?l[-~k]<w[-~k]?(g=_=>a[--i][k]<"+"?g(a[i][k]="|"):"+")():" ":(i=l=w,T)))


          Try it online!



          • thanks to @Arnauld for tio testing :)





          share|improve this answer


























            up vote
            2
            down vote














            JavaScript (Node.js), 125 122 118 117 bytes





            a=>a.map((w,i)=>a[i]=w.map((T,k)=>+i&&l[k]==T?l[-~k]<w[-~k]?(g=_=>a[--i][k]<"+"?g(a[i][k]="|"):"+")():" ":(i=l=w,T)))


            Try it online!



            • thanks to @Arnauld for tio testing :)





            share|improve this answer
























              up vote
              2
              down vote










              up vote
              2
              down vote










              JavaScript (Node.js), 125 122 118 117 bytes





              a=>a.map((w,i)=>a[i]=w.map((T,k)=>+i&&l[k]==T?l[-~k]<w[-~k]?(g=_=>a[--i][k]<"+"?g(a[i][k]="|"):"+")():" ":(i=l=w,T)))


              Try it online!



              • thanks to @Arnauld for tio testing :)





              share|improve this answer















              JavaScript (Node.js), 125 122 118 117 bytes





              a=>a.map((w,i)=>a[i]=w.map((T,k)=>+i&&l[k]==T?l[-~k]<w[-~k]?(g=_=>a[--i][k]<"+"?g(a[i][k]="|"):"+")():" ":(i=l=w,T)))


              Try it online!



              • thanks to @Arnauld for tio testing :)






              share|improve this answer














              share|improve this answer



              share|improve this answer








              edited Aug 17 at 19:23

























              answered Aug 17 at 16:06









              DanielIndie

              1,2105




              1,2105




















                  up vote
                  1
                  down vote













                  Python, 263 260 bytes



                  -3 bytes thanks to Jonathan Frech



                  Code:



                  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)


                  Try it Online!



                  Explanation:



                  This solution builds a trie out of the input words and recursively parses it into the required output. The a function takes a trie t and a string s and adds x to t. Tries are implemented as nested dictionaries. Each dictionary represents a node in the trie. For example, the dictionary representing the trie generated by the first test case looks like this:



                  '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': 


                  The p function recurses through this structure and generates the string representation of the trie expected by the challenge. The f function takes a bunch of strings as arguments, adds them all to a trie with a, then returns the result of calling p on the trie.






                  share|improve this answer


















                  • 1




                    Possible 252 bytes.
                    – Jonathan Frech
                    Aug 14 at 2:23














                  up vote
                  1
                  down vote













                  Python, 263 260 bytes



                  -3 bytes thanks to Jonathan Frech



                  Code:



                  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)


                  Try it Online!



                  Explanation:



                  This solution builds a trie out of the input words and recursively parses it into the required output. The a function takes a trie t and a string s and adds x to t. Tries are implemented as nested dictionaries. Each dictionary represents a node in the trie. For example, the dictionary representing the trie generated by the first test case looks like this:



                  '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': 


                  The p function recurses through this structure and generates the string representation of the trie expected by the challenge. The f function takes a bunch of strings as arguments, adds them all to a trie with a, then returns the result of calling p on the trie.






                  share|improve this answer


















                  • 1




                    Possible 252 bytes.
                    – Jonathan Frech
                    Aug 14 at 2:23












                  up vote
                  1
                  down vote










                  up vote
                  1
                  down vote









                  Python, 263 260 bytes



                  -3 bytes thanks to Jonathan Frech



                  Code:



                  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)


                  Try it Online!



                  Explanation:



                  This solution builds a trie out of the input words and recursively parses it into the required output. The a function takes a trie t and a string s and adds x to t. Tries are implemented as nested dictionaries. Each dictionary represents a node in the trie. For example, the dictionary representing the trie generated by the first test case looks like this:



                  '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': 


                  The p function recurses through this structure and generates the string representation of the trie expected by the challenge. The f function takes a bunch of strings as arguments, adds them all to a trie with a, then returns the result of calling p on the trie.






                  share|improve this answer














                  Python, 263 260 bytes



                  -3 bytes thanks to Jonathan Frech



                  Code:



                  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)


                  Try it Online!



                  Explanation:



                  This solution builds a trie out of the input words and recursively parses it into the required output. The a function takes a trie t and a string s and adds x to t. Tries are implemented as nested dictionaries. Each dictionary represents a node in the trie. For example, the dictionary representing the trie generated by the first test case looks like this:



                  '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': 


                  The p function recurses through this structure and generates the string representation of the trie expected by the challenge. The f function takes a bunch of strings as arguments, adds them all to a trie with a, then returns the result of calling p on the trie.







                  share|improve this answer














                  share|improve this answer



                  share|improve this answer








                  edited Aug 14 at 2:27

























                  answered Aug 14 at 2:06









                  Zachary Cotton

                  34915




                  34915







                  • 1




                    Possible 252 bytes.
                    – Jonathan Frech
                    Aug 14 at 2:23












                  • 1




                    Possible 252 bytes.
                    – Jonathan Frech
                    Aug 14 at 2:23







                  1




                  1




                  Possible 252 bytes.
                  – Jonathan Frech
                  Aug 14 at 2:23




                  Possible 252 bytes.
                  – Jonathan Frech
                  Aug 14 at 2:23










                  up vote
                  1
                  down vote














                  C (gcc), 165 155 bytes



                  Takes three arguments:




                  • char** a : an array of null-terminated words


                  • char* m : an array of the length of each word


                  • int n : the number of words in the array

                  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;


                  Try it online!






                  share|improve this answer


















                  • 1




                    Some quick wins
                    – Arnauld
                    Aug 14 at 10:08










                  • @Arnauld Of course! Although isn't ++i<n&j<m[i]&a[i--] undefined behavior? Can I rely on gcc evaluating it left to right?
                    – Curtis Bechtel
                    Aug 14 at 13:31










                  • It's very likely to be undefined behavior. But we define languages by their implementation, so as long as it works consistently with this version of gcc, I think that's fine.
                    – Arnauld
                    Aug 14 at 13:34














                  up vote
                  1
                  down vote














                  C (gcc), 165 155 bytes



                  Takes three arguments:




                  • char** a : an array of null-terminated words


                  • char* m : an array of the length of each word


                  • int n : the number of words in the array

                  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;


                  Try it online!






                  share|improve this answer


















                  • 1




                    Some quick wins
                    – Arnauld
                    Aug 14 at 10:08










                  • @Arnauld Of course! Although isn't ++i<n&j<m[i]&a[i--] undefined behavior? Can I rely on gcc evaluating it left to right?
                    – Curtis Bechtel
                    Aug 14 at 13:31










                  • It's very likely to be undefined behavior. But we define languages by their implementation, so as long as it works consistently with this version of gcc, I think that's fine.
                    – Arnauld
                    Aug 14 at 13:34












                  up vote
                  1
                  down vote










                  up vote
                  1
                  down vote










                  C (gcc), 165 155 bytes



                  Takes three arguments:




                  • char** a : an array of null-terminated words


                  • char* m : an array of the length of each word


                  • int n : the number of words in the array

                  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;


                  Try it online!






                  share|improve this answer















                  C (gcc), 165 155 bytes



                  Takes three arguments:




                  • char** a : an array of null-terminated words


                  • char* m : an array of the length of each word


                  • int n : the number of words in the array

                  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;


                  Try it online!







                  share|improve this answer














                  share|improve this answer



                  share|improve this answer








                  edited Aug 14 at 13:38

























                  answered Aug 14 at 5:40









                  Curtis Bechtel

                  29618




                  29618







                  • 1




                    Some quick wins
                    – Arnauld
                    Aug 14 at 10:08










                  • @Arnauld Of course! Although isn't ++i<n&j<m[i]&a[i--] undefined behavior? Can I rely on gcc evaluating it left to right?
                    – Curtis Bechtel
                    Aug 14 at 13:31










                  • It's very likely to be undefined behavior. But we define languages by their implementation, so as long as it works consistently with this version of gcc, I think that's fine.
                    – Arnauld
                    Aug 14 at 13:34












                  • 1




                    Some quick wins
                    – Arnauld
                    Aug 14 at 10:08










                  • @Arnauld Of course! Although isn't ++i<n&j<m[i]&a[i--] undefined behavior? Can I rely on gcc evaluating it left to right?
                    – Curtis Bechtel
                    Aug 14 at 13:31










                  • It's very likely to be undefined behavior. But we define languages by their implementation, so as long as it works consistently with this version of gcc, I think that's fine.
                    – Arnauld
                    Aug 14 at 13:34







                  1




                  1




                  Some quick wins
                  – Arnauld
                  Aug 14 at 10:08




                  Some quick wins
                  – Arnauld
                  Aug 14 at 10:08












                  @Arnauld Of course! Although isn't ++i<n&j<m[i]&a[i--] undefined behavior? Can I rely on gcc evaluating it left to right?
                  – Curtis Bechtel
                  Aug 14 at 13:31




                  @Arnauld Of course! Although isn't ++i<n&j<m[i]&a[i--] undefined behavior? Can I rely on gcc evaluating it left to right?
                  – Curtis Bechtel
                  Aug 14 at 13:31












                  It's very likely to be undefined behavior. But we define languages by their implementation, so as long as it works consistently with this version of gcc, I think that's fine.
                  – Arnauld
                  Aug 14 at 13:34




                  It's very likely to be undefined behavior. But we define languages by their implementation, so as long as it works consistently with this version of gcc, I think that's fine.
                  – Arnauld
                  Aug 14 at 13:34










                  up vote
                  1
                  down vote














                  Perl 6, 149 144 142 bytes





                  1 while s/(n.*)s(.*)$0(+o$_ Z$_).join("
                  ")


                  Try it online!



                  I'm sure this can be golfed a more, especially as I'm not an expert on regexes. This uses much the same process as Neil's Retina answer.






                  share|improve this answer


























                    up vote
                    1
                    down vote














                    Perl 6, 149 144 142 bytes





                    1 while s/(n.*)s(.*)$0(+o$_ Z$_).join("
                    ")


                    Try it online!



                    I'm sure this can be golfed a more, especially as I'm not an expert on regexes. This uses much the same process as Neil's Retina answer.






                    share|improve this answer
























                      up vote
                      1
                      down vote










                      up vote
                      1
                      down vote










                      Perl 6, 149 144 142 bytes





                      1 while s/(n.*)s(.*)$0(+o$_ Z$_).join("
                      ")


                      Try it online!



                      I'm sure this can be golfed a more, especially as I'm not an expert on regexes. This uses much the same process as Neil's Retina answer.






                      share|improve this answer















                      Perl 6, 149 144 142 bytes





                      1 while s/(n.*)s(.*)$0(+o$_ Z$_).join("
                      ")


                      Try it online!



                      I'm sure this can be golfed a more, especially as I'm not an expert on regexes. This uses much the same process as Neil's Retina answer.







                      share|improve this answer














                      share|improve this answer



                      share|improve this answer








                      edited Aug 17 at 12:30

























                      answered Aug 14 at 2:40









                      Jo King

                      14.9k24084




                      14.9k24084




















                          up vote
                          0
                          down vote














                          Python 2, 191 bytes





                          def f(w,r=['']):
                          for b,c in zip(w[1:],w)[::-1]:
                          s='';d=0
                          for x,y,z in zip(r[0]+b,b,c+b):t=s[-1:];s=s[:-1]+[['+'*(s>'')+y,t+' |'[x in'+|']][y==z],t+y][d];d=d|(y!=z)
                          r=[s]+r
                          return[w[0]]+r


                          Try it online!






                          share|improve this answer
























                            up vote
                            0
                            down vote














                            Python 2, 191 bytes





                            def f(w,r=['']):
                            for b,c in zip(w[1:],w)[::-1]:
                            s='';d=0
                            for x,y,z in zip(r[0]+b,b,c+b):t=s[-1:];s=s[:-1]+[['+'*(s>'')+y,t+' |'[x in'+|']][y==z],t+y][d];d=d|(y!=z)
                            r=[s]+r
                            return[w[0]]+r


                            Try it online!






                            share|improve this answer






















                              up vote
                              0
                              down vote










                              up vote
                              0
                              down vote










                              Python 2, 191 bytes





                              def f(w,r=['']):
                              for b,c in zip(w[1:],w)[::-1]:
                              s='';d=0
                              for x,y,z in zip(r[0]+b,b,c+b):t=s[-1:];s=s[:-1]+[['+'*(s>'')+y,t+' |'[x in'+|']][y==z],t+y][d];d=d|(y!=z)
                              r=[s]+r
                              return[w[0]]+r


                              Try it online!






                              share|improve this answer













                              Python 2, 191 bytes





                              def f(w,r=['']):
                              for b,c in zip(w[1:],w)[::-1]:
                              s='';d=0
                              for x,y,z in zip(r[0]+b,b,c+b):t=s[-1:];s=s[:-1]+[['+'*(s>'')+y,t+' |'[x in'+|']][y==z],t+y][d];d=d|(y!=z)
                              r=[s]+r
                              return[w[0]]+r


                              Try it online!







                              share|improve this answer












                              share|improve this answer



                              share|improve this answer










                              answered Aug 14 at 18:06









                              Chas Brown

                              4,1361319




                              4,1361319




















                                  up vote
                                  0
                                  down vote














                                  Ruby, 118 bytes





                                  ->ai=1;a.maps="";a[i+=j=-1].charsc[/[


                                  Try it online!



                                  Accepts an array of strings, outputs by modifying the original input array in-place.



                                  Explanation



                                  The basic string transformation is not too complex, but in order to insert vertical pipes properly, we need to iterate in reverse order, and since reverse method is quite verbose, we'll do it in a trickier way. Here, we use map just to run the loop, leave the first word alone, and then iterate from the end using negative indices:



                                  ->a
                                  i=1; #Initialize word indexer
                                  a.map at word boundary with +







                                  share|improve this answer


























                                    up vote
                                    0
                                    down vote














                                    Ruby, 118 bytes





                                    ->ai=1;a.maps="";a[i+=j=-1].charsc[/[


                                    Try it online!



                                    Accepts an array of strings, outputs by modifying the original input array in-place.



                                    Explanation



                                    The basic string transformation is not too complex, but in order to insert vertical pipes properly, we need to iterate in reverse order, and since reverse method is quite verbose, we'll do it in a trickier way. Here, we use map just to run the loop, leave the first word alone, and then iterate from the end using negative indices:



                                    ->a
                                    i=1; #Initialize word indexer
                                    a.map at word boundary with +







                                    share|improve this answer
























                                      up vote
                                      0
                                      down vote










                                      up vote
                                      0
                                      down vote










                                      Ruby, 118 bytes





                                      ->ai=1;a.maps="";a[i+=j=-1].charsc[/[


                                      Try it online!



                                      Accepts an array of strings, outputs by modifying the original input array in-place.



                                      Explanation



                                      The basic string transformation is not too complex, but in order to insert vertical pipes properly, we need to iterate in reverse order, and since reverse method is quite verbose, we'll do it in a trickier way. Here, we use map just to run the loop, leave the first word alone, and then iterate from the end using negative indices:



                                      ->a
                                      i=1; #Initialize word indexer
                                      a.map at word boundary with +







                                      share|improve this answer















                                      Ruby, 118 bytes





                                      ->ai=1;a.maps="";a[i+=j=-1].charsc[/[


                                      Try it online!



                                      Accepts an array of strings, outputs by modifying the original input array in-place.



                                      Explanation



                                      The basic string transformation is not too complex, but in order to insert vertical pipes properly, we need to iterate in reverse order, and since reverse method is quite verbose, we'll do it in a trickier way. Here, we use map just to run the loop, leave the first word alone, and then iterate from the end using negative indices:



                                      ->a
                                      i=1; #Initialize word indexer
                                      a.map at word boundary with +








                                      share|improve this answer














                                      share|improve this answer



                                      share|improve this answer








                                      edited Aug 17 at 13:56

























                                      answered Aug 17 at 12:02









                                      Kirill L.

                                      2,4061116




                                      2,4061116



























                                           

                                          draft saved


                                          draft discarded















































                                           


                                          draft saved


                                          draft discarded














                                          StackExchange.ready(
                                          function ()
                                          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodegolf.stackexchange.com%2fquestions%2f170580%2fmake-an-alphabetrie%23new-answer', 'question_page');

                                          );

                                          Post as a guest













































































                                          Comments

                                          Popular posts from this blog

                                          What does second last employer means? [closed]

                                          Installing NextGIS Connect into QGIS 3?

                                          One-line joke