Horizontally Aligned ASCII Art

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"

• Can we use a custom delimiter instead of newlines? i.e. "|" or " "? Mar 16, 2018 at 15:30
• I'm gonna say no given that would kind of ruin any art. Mar 16, 2018 at 15:31
• May we use \r instead of \n?
Mar 16, 2018 at 15:50
• @Adám Sure. I'll update the wording. Mar 16, 2018 at 15:52
Mar 16, 2018 at 15:53

Canvas, 1 byte

×


Try it here!

• Cause who doesn't just have a builtin for this? :P Mar 16, 2018 at 15:49
• That's not even fair. ;-; Mar 16, 2018 at 15:52
• @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. Mar 16, 2018 at 16:43
• @KevinCruijssen although I just remembered that I have a built-in for reverse add, so I'm updating the post :p Mar 16, 2018 at 16:45
• So Canvas has two builtins for this? Ok, why not? Mar 16, 2018 at 20:11

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


Try it online!

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

Python 2, 59 bytes

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


Try it online!

• It can also be shortened by removing the space. :P Mar 16, 2018 at 15:27
• If you want to input and output lists of lines, as you had before, you can get it down to 30: Try it online!
– user48543
Mar 16, 2018 at 15:43
• 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. Mar 16, 2018 at 16:40

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

• Too bad a space between the two inputs wasn't allowed :(. Mar 16, 2018 at 16:44

Jelly, 4 bytes

Ỵ€ZY


Try it online!

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! Bash + coreutils, 14 • 4 bytes saved thanks to @DavidFoerster. paste -d ""$@


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

• You can save 4 bytes: paste -d "" $@ Mar 16, 2018 at 20:50 • @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 Mar 16, 2018 at 21:38 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~].

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)

Java 8, 10084 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

• 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. Mar 16, 2018 at 17:07
• @OlivierGrégoire Thanks! And exiting with an error to STDERR is indeed allowed after it has printed everything to STDOUT. Mar 16, 2018 at 17:53

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. 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>") 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. Kotlin, 73 bytes a,b->a.split("\n").mapIndexed{i,s->s+b.split("\n")[i]}.joinToString("\n")  Try it online! Vyxalj, 4 bytes ↵∩vṅ  Try it Online! K (ngn/k), 15 14 bytes "\n"/,'/"\n"\'  Try it online! -1 byte thanks to ngn • ,/'+ -> ,'/ – ngn May 19 at 16:52 Add++, 24 bytes L,c10CdVAptA$pG$tBcB@£+n  Try it online! 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! 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! 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. APL (Dyalog Unicode), 22 bytes (Adám's SBCS) {⊃,/↑¨⍵}'[^\n]+'⎕S'&'¨  Try it online! Red, 78 bytes func[a b][b: split b"^/"foreach c split a"^/"[prin c print first b b: next b]]  Try it online! 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


Charcoal, 8 bytes

ＰθＭ⌕θ¶→η


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

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


Add 2 bytes to accept multiple inputs:

ＦＡ«ＰιＭ⌕ι¶→


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

 Ａ          Input
Ｆ «         Loop over all entries
Ｐι       Print current entry
Ｍ⌕ι¶→  Move to next entry


ＰθＭ⌈Ｅ⪪θ¶Ｌι→η


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

      θ         First input
¶        Literal newline
⪪          Split
Ｅ           Map over each string
ι      Current string
Ｌ       Length
⌈            Maximum
Ｍ       →     Move that many squares right


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

Clean, 61 bytes

import StdEnv
$a b=flatlines[u++v\\u<-mklines a&v<-mklines b]  Try it online! 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!

Julia 1.0, 34 bytes

^,x=split,"\n"
a\b=join(a^x.*b^x,x)


Try it online!

Wolfram Language (Mathematica), 43 bytes (41 chars)

Column[StringJoin/@(#~StringSplit~"
")]&


 is an unprintable character in the private use area which represents Transpose in Mathematica.

This function takes input as a list of any number of strings and returns a Column object, which displays in a Mathematica notebook in the required manner (although it doesn't on TIO). For an additional ten bytes, replacing Column[---] with StringRiffle[---," "] will cause an output in the form of a single string. This code can take input of any number of strings with varied-length lines, as long as each string has the same number of lines.

Explanation:

#~StringSplit~ Split the input (implicitly applied to each string in the list)

" " at each newline.

 Then, transpose this list of lists of strings

StringJoin/@ and join together each of the sublists.

Column Finally, convert this list of strings to a Column object.

Try it online!

• Just out of curiosity, how did you come by my challenge? There's been like four very recent submissions to a challenge I posted 4 years ago. May 3 at 15:47
• It popped up on the recently answered questions (probably from Steffan's Vyxal answer) and so I decided to do it. May 3 at 15:49

Japt-R, 87 5 bytes

·í+V·


Try it

·í+V·     :Implcict input of strings U & V
·         :Split U on newlines
í        :Interleave with
V·     :  V split on newlines
+       :  Reduce by concatenation
:Implicit output, joined by newlines
`