20
\$\begingroup\$

Your task is to accept as input two "ASCII Art"s, and align each piece of art next to each other horizontally.

For example, say you have two strings, "abc\ndef" and "123\n456". You need to align them horizontally to produce the string "abc123\ndef456". I'm calling this "aligning horizontally" because while the inputs, when printed, look like this:

abc
def

and:

123
456

The output, when printed, will look like this:

abc123
def456

Note how one input is placed next to the other.


Input

  • Input will be strings, and can be as two separate arguments, or as a sequence of strings.
  • The characters in the arts will have decimal codes in the range 32-126 (inclusive).
  • It's fine to support an arbitrary number of arts to align instead of just two (but obviously you must support at least two).
  • You can assume that each art will have the same dimensions, and that they will contain at least one line.
  • You must be able to support at least 100x100 character arts.

  • To align with conventions on the site, the argument order does not matter. It does not matter which art is on the left or right.


Output

  • Output will be the aligned arts as mentioned above, either returned or output to the stdout.

  • Any trailing whitespace in optional.

  • There must be no visual separator between the aligned arts.


Input and output arts must be \n or \r delimited strings. It would be overly trivial to allow 2D-arrays.

Submissions may be functions or full programs.

Test Cases:

"abc\ndef", "123\n456" -> "abc123\ndef456".

"qwertyuiop\n asdfghjkl", "Some other\nTextFiller" -> "qwertyuiopSome other\n asdfghjklTextFiller"

"  *  \n *** \n*****\n *** \n  *  \n", "  +  \n  +  \n+++++\n  +  \n  +  \n" -> "  *    +  \n ***   +  \n*****+++++\n ***   +  \n  *    +  \n"
\$\endgroup\$
  • 1
    \$\begingroup\$ Can we use a custom delimiter instead of newlines? i.e. "|" or " "? \$\endgroup\$ – Rɪᴋᴇʀ Mar 16 '18 at 15:30
  • 10
    \$\begingroup\$ I'm gonna say no given that would kind of ruin any art. \$\endgroup\$ – Carcigenicate Mar 16 '18 at 15:31
  • \$\begingroup\$ May we use \r instead of \n? \$\endgroup\$ – Adám Mar 16 '18 at 15:50
  • \$\begingroup\$ @Adám Sure. I'll update the wording. \$\endgroup\$ – Carcigenicate Mar 16 '18 at 15:52
  • \$\begingroup\$ Is leading whitespace ok? \$\endgroup\$ – Adám Mar 16 '18 at 15:53

27 Answers 27

20
\$\begingroup\$

Canvas, 1 byte

×

Try it here!

\$\endgroup\$
  • 6
    \$\begingroup\$ Cause who doesn't just have a builtin for this? :P \$\endgroup\$ – caird coinheringaahing Mar 16 '18 at 15:49
  • 5
    \$\begingroup\$ That's not even fair. ;-; \$\endgroup\$ – totallyhuman Mar 16 '18 at 15:52
  • 3
    \$\begingroup\$ @KevinCruijssen On PPCG it's usually allowed to take inputs in whatever order you want, and for a stack-based language the current order makes more sense than reverse. \$\endgroup\$ – dzaima Mar 16 '18 at 16:43
  • 5
    \$\begingroup\$ @KevinCruijssen although I just remembered that I have a built-in for reverse add, so I'm updating the post :p \$\endgroup\$ – dzaima Mar 16 '18 at 16:45
  • 2
    \$\begingroup\$ So Canvas has two builtins for this? Ok, why not? \$\endgroup\$ – caird coinheringaahing Mar 16 '18 at 20:11
7
\$\begingroup\$

Haskell, 37 bytes

(unlines.).(.lines).zipWith(++).lines

Try it online!

IO as lists of lines would just be zipWith(++). :P

\$\endgroup\$
6
\$\begingroup\$

Python 2, 59 bytes

lambda y:'\n'.join(map(str.__add__,*map(str.splitlines,y)))

Try it online!

\$\endgroup\$
  • \$\begingroup\$ It can also be shortened by removing the space. :P \$\endgroup\$ – totallyhuman Mar 16 '18 at 15:27
  • \$\begingroup\$ If you want to input and output lists of lines, as you had before, you can get it down to 30: Try it online! \$\endgroup\$ – Mnemonic Mar 16 '18 at 15:43
  • \$\begingroup\$ I sat there for like 5 minutes trying to decide if I should allow that. As the Haskell answer shows, it would reduce the challenge down to something much more trivial. I suppose though that the overly trivial solutions just wouldn't be as popular. \$\endgroup\$ – Carcigenicate Mar 16 '18 at 16:40
4
\$\begingroup\$

05AB1E, 6 bytes

|¶¡øJ»

Try it online!

Explanation

|        # push all input into a list
 ¶¡      # split on newlines
   ø     # zip
    J    # join the rows to single strings
     »   # merge on newlines
\$\endgroup\$
  • \$\begingroup\$ Too bad a space between the two inputs wasn't allowed :(. \$\endgroup\$ – Magic Octopus Urn Mar 16 '18 at 16:44
3
\$\begingroup\$

Jelly, 4 bytes

Ỵ€ZY

Try it online!

\$\endgroup\$
3
\$\begingroup\$

Perl 5 -0F, 28 bytes

Includes +2 for the \n argument to -F (it's "code" so it should count)

Give inputs directly after each other on STDIN.

#!/usr/bin/perl -0F\n
say@F[$%++,$_]for@F/2..$#F

Try it online!

\$\endgroup\$
3
\$\begingroup\$

Bash + coreutils, 14

  • 4 bytes saved thanks to @DavidFoerster.
paste -d "" $@

Input is given as two filenames as command-line parameters.

Try it online.

\$\endgroup\$
  • \$\begingroup\$ You can save 4 bytes: paste -d "" $@ \$\endgroup\$ – David Foerster Mar 16 '18 at 20:50
  • \$\begingroup\$ @DavidFoerster Thanks! Weird - I tried that earlier and it didn't work. Edit - I see now - instead of -d "", I tried -d"", which of course is no different to -d \$\endgroup\$ – Digital Trauma Mar 16 '18 at 21:38
3
\$\begingroup\$

Perl 6, 27 bytes

{join "\n",[Z~] $_>>.lines}

Try it online!

Works with arbitrary number of arts. IO as list of lists would be just &[Z~].

\$\endgroup\$
2
\$\begingroup\$

APL (Dyalog Unicode), 9 bytesSBCS

Full program. Prompts (STDIN) for any length list of \r-delimited strings. The strings may be ragged and of different widths as long as they have the same number of lines. Prints (STDOUT) resulting ASCII art.

⊃,/⎕FMT¨⎕

Try it online!

 prompt for evaluated input

⎕FMT¨ format (evaluate all control characters and return character matrix) each

,/ combine them horizontally (catenation reduction)

 disclose (because the reduction reduced the rank from 1 to 0)

\$\endgroup\$
2
\$\begingroup\$

Java 8, 100 84 78 bytes

a->b->{for(int i=0;;)System.out.println(a.split("\n")[i]+b.split("\n")[i++]);}

Exits with an ArrayIndexOutOfBoundsException to STDERR after it has printed the result to STDOUT, which is allowed.

-6 bytes thanks to @OlivierGrégoire.

Explanation:

Try it online.

a->b->{                        // Method with two String parameters and no return-type
  for(int i=0;;)               //  Loop over the substrings of the first input
    System.out.println(        //   Print:
     a.split("\n")[i]          //    The substring of the first input
     +b.split("\n")[i++]);}    //    plus the same-indexed substring of the second input
\$\endgroup\$
  • 1
    \$\begingroup\$ a->b->{for(int i=0;;)System.out.println(a.split("\n")[i]+b.split("\n")[i++]);} 78 bytes. Nothing is said about not having any extra side-effect. So we could simply count until an exception occurs. \$\endgroup\$ – Olivier Grégoire Mar 16 '18 at 17:07
  • \$\begingroup\$ @OlivierGrégoire Thanks! And exiting with an error to STDERR is indeed allowed after it has printed everything to STDOUT. \$\endgroup\$ – Kevin Cruijssen Mar 16 '18 at 17:53
2
\$\begingroup\$

Ruby, 48 bytes

->a,b{$;=$/;a.split.zip(b.split).map(&:join)*$/}

Try it online!

A lambda taking two strings and returning a string. Setting the default split delimiter to newline with $;=$/; doesn't save any bytes, but it makes the rest look a little nicer.

Ruby, 49 bytes (arbitrarily many strings)

->s{s.map{|a|a.split$/}.transpose.map(&:join)*$/}

Try it online!

Just for fun. It turns out we can accept an array of strings at an additional cost of only 1 byte.

\$\endgroup\$
2
\$\begingroup\$

JavaScript (ES6), 51 bytes

f=
(a,b)=>a.replace(/.+/g,a=>a+b.shift(),b=b.split`
`)
;document.write("<pre>"+f("abc\ndef", "123\n456")+"</pre>")

\$\endgroup\$
2
\$\begingroup\$

Wonder, 21 bytes

->#oN.zip#++.-> <>"
"

Usage example:

(->#oN.zip#++.-> <>"
")["abc#ndef" "abc#ndef"]

#n is used instead of \n to denote newlines.

Explanation

Verbose version:

(map #oN) . (zip #con) . (map split "#n")

Split each string in the input array along newlines, zip with string concatenate, and output each item.

\$\endgroup\$
2
\$\begingroup\$

Kotlin, 73 bytes

a,b->a.split("\n").mapIndexed{i,s->s+b.split("\n")[i]}.joinToString("\n")

Try it online!

\$\endgroup\$
1
\$\begingroup\$

Add++, 24 bytes

L,c10CdVAptA$pG$tBcB@£+n

Try it online!

\$\endgroup\$
1
\$\begingroup\$

C, 96 bytes

#define L(s)for(;*s++>10;)putchar(s[-1]);
i;f(s,t)char*s,*t;{for(;i=!!s[-i];puts("")){L(s)L(t)}}

Try it online!

\$\endgroup\$
1
\$\begingroup\$

JavaScript (ES6), 52 bytes

Takes input in currying syntax (a)(b).

a=>b=>a.split`
`.map((s,i)=>s+b.split`
`[i]).join`
`

Try it online!

\$\endgroup\$
1
\$\begingroup\$

Julia 0.6, 41 bytes

(a,b)->map(*,split(a,'\n'),split(b,'\n'))

Try it online!

\$\endgroup\$
1
\$\begingroup\$

PowerShell, 51 49 bytes

param($a,$b)$a-split"
"|%{$_+($b-split"
")[$i++]}

Try it online!

Takes input as literal strings with newlines. You could also use `n (the newline delimiter in PowerShell, not \n) instead.

We first -split the left input string on newlines, which creates an array, and loop through that |%{...}. Each iteration, we string concatenate with the right input string again split on newlines, indexed and incremented.

Those are left on the pipeline and the implicit Write-Output at completion gives us output as an array of strings, which are printed with newlines between.

\$\endgroup\$
1
\$\begingroup\$

APL (Dyalog Unicode), 22 bytes (Adám's SBCS)

{⊃,/↑¨⍵}'[^\n]+'⎕S'&'¨

Try it online!

\$\endgroup\$
1
\$\begingroup\$

Red, 78 bytes

func[a b][b: split b"^/"foreach c split a"^/"[prin c print first b b: next b]]

Try it online!

\$\endgroup\$
1
\$\begingroup\$

Japt -R, 8 7 bytes

·íV· m¬

Try it


Explanation

             :Implicit input of strings U & V
·            :Split U on newlines
  V·         :Split V on newlines
 í           :Interleave
     m       :Map
      ¬      :  Join
             :Implicitly join with newlines and output

Alternative

·Ë+V·gE

Try it

             :Implicit input of strings U & V
·            :Split U on newlines
 Ë           :Map over each element at index E and rejoin with newlines
   V·        :  Split V on newlines
     gE      :  Get the element at index E
  +          :  Append to the current element
             :Implicitly join with newlines and output
\$\endgroup\$
1
\$\begingroup\$

Bash, 92 bytes

a=();for b;do c=;while IFS= read -r d;do a[c++]+=$d;done<<<"$b";done;printf '%s\n' "${a[@]}"

Try it online!

Ungolfed:

array=()                             # Initialize the array
for argument in "${@}"; do           # Loop over the arguments list
  index='0'                          # Reset the index
  while IFS='' read -r 'line'; do    # Loop over every line of the current argument
    array[index]+="${line}"          # Append the line to its corresponding place
    (( index++ ))                    # Increment the index
  done <<< "${argument}"             # End while loop
done                                 # End for loop
printf '%s\n' "${array[@]}"          # Print array's content

Examples:

$ foo $'abc\ndef' $'123\n456'
abc123
def456

$ foo $'qwertyuiop\n asdfghjkl' $'Some other\nTextFiller'
qwertyuiopSome other
 asdfghjklTextFiller

$ foo \
>   $'  *  \n *** \n*****\n *** \n  *  \n' \
>   $'  +  \n  +  \n+++++\n  +  \n  +  \n'
  *    +  
 ***   +  
*****+++++
 ***   +  
  *    +  


# https://gist.github.com/nxnev/dad0576be7eb2996b860c320c01d0ec5
$ foo "$(< input1)" "$(< input2)" "$(< input3)" > output

I also have a shorter one but it fails if the second read statement returns a non-zero value.

Bash, 55 bytes

while IFS= read -r a;IFS= read b<&3;do echo "$a$b";done

Note: <&3 doesn't seem to work on tio.run

This one uses file descriptors (1 and 3) instead of arguments:

$ foo <<< $'qwertyuiop\n asdfghjkl' 3<<< $'Some other\nTextFiller'
qwertyuiopSome other
 asdfghjklTextFiller
\$\endgroup\$
1
\$\begingroup\$

Charcoal, 8 bytes

PθM⌕θ¶→η

Try it online! Link is to verbose version of code. Explanation:

 θ          First input
P           Print without moving the cursor
    θ       First input
     ¶      Literal newline
   ⌕        Find index
  M   →     Move that many squares right
       η    Implicitly print second input

Add 2 bytes to accept multiple inputs:

FA«PιM⌕ι¶→

Try it online! Link is to verbose version of code. Explanation:

 A          Input
F «         Loop over all entries
   Pι       Print current entry
     M⌕ι¶→  Move to next entry

Add 4 bytes to accept unpadded input:

PθM⌈E⪪θ¶Lι→η

Try it online! Link is to verbose version of code. Explanation:

      θ         First input
       ¶        Literal newline
     ⪪          Split
    E           Map over each string
         ι      Current string
        L       Length
   ⌈            Maximum
  M       →     Move that many squares right
\$\endgroup\$
1
\$\begingroup\$

JavaScript (Node.js), 79 bytes

a=>(b=a.map(x=>x.split`
`))[i=0].map(y=>b.map(z=>c+=z[i],c="")&&++i&&c).join`
`

Try it online!

Supports arbitrary number of ASCII arts joining together rather than just 2 (as in the 2 previous JS answers).

\$\endgroup\$
1
\$\begingroup\$

Clean, 61 bytes

import StdEnv
$a b=flatlines[u++v\\u<-mklines a&v<-mklines b]

Try it online!

\$\endgroup\$
1
\$\begingroup\$

Swift 4, 119 bytes

func f(s:[String])->String{return s[0].split{$0=="\n"}.enumerated().map{$0.1+s[1].split{$0=="\n"}[$0.0]+"\n"}.joined()}

Explanation

func f(s: [String]) -> String {
    return s[0].split{ $0=="\n" }       //splitting the first string after every \n
    .enumerated()                       //create a tuple of offsets and elements
    .map {
        $0.1 +                          //current element
        s[1].split{$0 == "\n"}[$0.0] +  //splitting the second string + indexing
        "\n"                            //new line after every line
     }
     .joined()
}

Try it online!

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.