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"
31 Answers 31
-
6\$\begingroup\$ Cause who doesn't just have a builtin for this? :P \$\endgroup\$2018年03月16日 15:49:18 +00:00Commented Mar 16, 2018 at 15:49
-
5\$\begingroup\$ That's not even fair. ;-; \$\endgroup\$totallyhuman– totallyhuman2018年03月16日 15:52:12 +00:00Commented Mar 16, 2018 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– dzaima2018年03月16日 16:43:31 +00:00Commented Mar 16, 2018 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– dzaima2018年03月16日 16:45:36 +00:00Commented Mar 16, 2018 at 16:45
-
3\$\begingroup\$ So Canvas has two builtins for this? Ok, why not? \$\endgroup\$2018年03月16日 20:11:57 +00:00Commented Mar 16, 2018 at 20:11
Haskell, 37 bytes
(unlines.).(.lines).zipWith(++).lines
IO as lists of lines would just be zipWith(++). :P
-
\$\begingroup\$ It can also be shortened by removing the space. :P \$\endgroup\$totallyhuman– totallyhuman2018年03月16日 15:27:09 +00:00Commented Mar 16, 2018 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\$user48543– user485432018年03月16日 15:43:55 +00:00Commented Mar 16, 2018 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– Carcigenicate2018年03月16日 16:40:06 +00:00Commented Mar 16, 2018 at 16:40
05AB1E, 6 bytes
|¶¡øJ»
Explanation
| # push all input into a list
¶¡ # split on newlines
ø # zip
J # join the rows to single strings
» # merge on newlines
-
\$\begingroup\$ Too bad a space between the two inputs wasn't allowed :(. \$\endgroup\$Magic Octopus Urn– Magic Octopus Urn2018年03月16日 16:44:24 +00:00Commented Mar 16, 2018 at 16:44
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
Bash + coreutils, 14
- 4 bytes saved thanks to @DavidFoerster.
paste -d "" $@
Input is given as two filenames as command-line parameters.
-
\$\begingroup\$ You can save 4 bytes:
paste -d "" $@\$\endgroup\$David Foerster– David Foerster2018年03月16日 20:50:11 +00:00Commented Mar 16, 2018 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– Digital Trauma2018年03月16日 21:38:41 +00:00Commented Mar 16, 2018 at 21:38
APL (Dyalog Unicode), 9 bytes SBCS
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 ̈⎕
⎕ 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, (削除) 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:
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
-
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– Olivier Grégoire2018年03月16日 17:07:04 +00:00Commented Mar 16, 2018 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– Kevin Cruijssen2018年03月16日 17:53:30 +00:00Commented Mar 16, 2018 at 17:53
Ruby, 48 bytes
->a,b{$;=$/;a.split.zip(b.split).map(&:join)*$/}
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)*$/}
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")
-
1\$\begingroup\$
,/'+->,'/\$\endgroup\$ngn– ngn2022年05月19日 16:52:27 +00:00Commented May 19, 2022 at 16:52
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)}}
JavaScript (ES6), 52 bytes
Takes input in currying syntax (a)(b).
a=>b=>a.split`
`.map((s,i)=>s+b.split`
`[i]).join`
`
PowerShell, (削除) 51 (削除ここまで) 49 bytes
param($a,$b)$a-split"
"|%{$_+($b-split"
")[$i++]}
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.
Red, 78 bytes
func[a b][b: split b"^/"foreach c split a"^/"[prin c print first b b: next b]]
Bash, 92 bytes
a=();for b;do c=;while IFS= read -r d;do a[c++]+=$d;done<<<"$b";done;printf '%s\n' "${a[@]}"
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
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
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`
`
Supports arbitrary number of ASCII arts joining together rather than just 2 (as in the 2 previous JS answers).
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()
}
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.
-
\$\begingroup\$ 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. \$\endgroup\$Carcigenicate– Carcigenicate2022年05月03日 15:47:50 +00:00Commented May 3, 2022 at 15:47
-
\$\begingroup\$ It popped up on the recently answered questions (probably from Steffan's Vyxal answer) and so I decided to do it. \$\endgroup\$Romanp– Romanp2022年05月03日 15:49:48 +00:00Commented May 3, 2022 at 15:49
Japt -R, (削除) 8 (削除ここまで) (削除) 7 (削除ここまで) 5 bytes
·í+V·
·í+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
"|"or" "? \$\endgroup\$\rinstead of\n? \$\endgroup\$