14
\$\begingroup\$

Challenge

Write a program that applies an injective function which takes an ordered pair of strings as input and one string as output. In other words, each input must map to a unique output.

Specifics

  • The input may be any two strings of arbitrary length, but will consist only of printable ASCII characters (codes \$[32, 126]\$).
  • Similarly, the output string has no length restriction, but it must consist only of printable ASCII characters.
  • If your language can't handle arbitrary-length strings, the program may merely work theoretically for strings of any size.
  • The mapping from inputs to outputs should be consistent between executions of the program. Otherwise, the mapping you use is completely up to you, as long as it is an injection.
  • The input is ordered. If the two input strings are different, they should produce a different output than if they were swapped. \$s \neq t \implies f(s, t) \neq f(t, s)\$
  • Not every string needs to be a possible output.
  • The shortest answer in each language wins!

Test cases

The following inputs should all result in different outputs. To avoid confusion, strings are surrounded by guillemets («») and separated by single spaces.

«hello» «world»
«lelho» «drowl»
«diffe» «_rent»
«notth» «esame»

«Code» «Golf»
«Co» «deGolf»
«CodeGolf» «»

«» «»
«» « »
« » «»
« » «  »
«  » « »

«abc", » «def»
«abc» «, "def»
«abc' » «'def»
«abc'» « 'def»

«\» «"»
«\\» «\"»
\$\endgroup\$
10
  • 8
    \$\begingroup\$ Hmm I just noticed "Write a program that..." - note that by meta consensus (currently 46 up, 1 down) "Restricting to just programs requires explicitly specifying "full program" rather than just "program"". I hope you did not mean to try to restrict this, but if you did you'll need to update the post accordingly and address those of us which have already submitted functions as answers. \$\endgroup\$ Sep 27, 2019 at 17:26
  • 4
    \$\begingroup\$ @JonathanAllan The intent was to allow functions. \$\endgroup\$ Sep 27, 2019 at 22:25
  • 3
    \$\begingroup\$ Can either of the strings be empty? \$\endgroup\$
    – Shaggy
    Sep 27, 2019 at 22:49
  • 2
    \$\begingroup\$ @Shaggy Yes, either or both can. \$\endgroup\$ Sep 28, 2019 at 7:17
  • 1
    \$\begingroup\$ Can we have some test cases? Thanks! \$\endgroup\$
    – ouflak
    Sep 28, 2019 at 13:18

28 Answers 28

18
\$\begingroup\$

brainfuck, 30 29 27 23 bytes

,[-[+.>]-[>+<---]>.-.,]

Try it online!

Inputs are separated by a 0x01 byte.

This turns ["foo", "bar"] into fUToUToUTUTbUTaUTrUT. To recover the original two strings, take groups of 3 characters, find the one where the second letter isn't U, and split there.

\$\endgroup\$
1
  • \$\begingroup\$ @Grimy Sorry, misunderstood "Inputs are separated by a 0x01 byte." \$\endgroup\$
    – wastl
    Sep 28, 2019 at 11:02
17
\$\begingroup\$

JavaScript (ES6), 14 bytes

Takes input as an array of 2 strings. Inspired by Luis' answer.

JSON.stringify

Try it online!


JavaScript (ES6),  21  20 bytes

Takes input as (a)(b).

a=>b=>[a.length,a]+b

Try it online!

Returns the length of \$a\$, followed by a comma, followed by the concatenation of \$a\$ and \$b\$.

\$\endgroup\$
5
  • \$\begingroup\$ Goddamnit! Was just about to use the stringify trick myself! \$\endgroup\$
    – Shaggy
    Sep 27, 2019 at 17:25
  • \$\begingroup\$ Breaks with a="hello","" b="world" and a="hello" b="","world" \$\endgroup\$
    – Soleil
    Sep 28, 2019 at 18:17
  • 1
    \$\begingroup\$ @Soleil That would give ["\"hello\",\"\"","\"world\""] and ["\"hello\"","\"\",\"world\""]. \$\endgroup\$
    – Arnauld
    Sep 28, 2019 at 18:51
  • 1
    \$\begingroup\$ @Arnauld the backslash protection won't be visible. The function won't inject. \$\endgroup\$
    – Soleil
    Sep 28, 2019 at 18:54
  • 1
    \$\begingroup\$ @Soleil I don't understand what you mean. JSON.stringify() definitely escapes ". See a hex dump. \$\endgroup\$
    – Arnauld
    Sep 28, 2019 at 19:06
15
\$\begingroup\$

jq -c, 0 bytes

Try it online!

This definitely feels like cheating...? But it seems to comply with the rules of the challenge.

By default, jq will output its input in a human-readable JSON format. The -c (compact) flag tells jq to output in "compact" style, which removes the newlines (since the challenge forbids non-printable ASCII).

\$\endgroup\$
3
  • 1
    \$\begingroup\$ OP allows empty input, so wouldn't a="", b="x" give same output as a="x" b="" \$\endgroup\$
    – Gnudiff
    Sep 28, 2019 at 13:37
  • 3
    \$\begingroup\$ @Gnudiff How so? They would give ["","x"] and ["x",""] respectively \$\endgroup\$
    – Doorknob
    Sep 28, 2019 at 15:54
  • 1
    \$\begingroup\$ Sorry, you're right. \$\endgroup\$
    – Gnudiff
    Sep 28, 2019 at 17:34
7
\$\begingroup\$

Python 3, 3 bytes

str

A (built-in) function which, given a list of the two strings, gives a string representation of the list

Try it online!

\$\endgroup\$
2
  • 2
    \$\begingroup\$ More pithy than Pyth... \$\endgroup\$ Sep 30, 2019 at 20:23
  • 1
    \$\begingroup\$ Well, the 1 byte Pyth solution ` does the same thing. \$\endgroup\$ Oct 1, 2019 at 6:47
5
\$\begingroup\$

Japt -S, 3 bytes

I still feel I must be missing something here ...

®mc

Try it

Possibly 2 bytes:

mq

Try it

Or stretching it with this 1-byter:

U

Try it

The first version maps each string in the array to its codepoints and outputs them joined with a space.

The second version splits each string to a character array and outputs them joined with a space.

And the third version, which feels like cheating, just outputs the input with the -Q flag doing the heavy lifting of srringifying it.

\$\endgroup\$
0
5
\$\begingroup\$

Haskell, 4 bytes

show

The Haskell built-in to turn things into strings. The input is taken as a pair of strings.

Try it online!

\$\endgroup\$
0
5
\$\begingroup\$

Pyth, 4 bytes

jNmC

Try it online!

This converts each string to base 256 and then joins them in order with a ". Since the results are each numbers the " unambiguously separates them and the original strings can be recovered with mCsdczN.

\$\endgroup\$
3
  • 1
    \$\begingroup\$ @AndersKaseorg suggests a 1-byter. \$\endgroup\$ Oct 1, 2019 at 7:11
  • \$\begingroup\$ @KevinCruijssen I've been aware of that since a few minutes after I posted this, I just prefer the spirit of this solution. Thanks for bringing it up anyway, and definitely feel free to post it yourself :) \$\endgroup\$ Oct 1, 2019 at 14:41
  • \$\begingroup\$ I indeed like your answer more as well. :) And nah, I don't even know Pyth. If you want you can post it yourself as a separated answer (or a combined answer by editing this one), otherwise Anders Kaseorg can post it, since he's the one who mentioned it in the comment. \$\endgroup\$ Oct 1, 2019 at 15:13
4
\$\begingroup\$

T-SQL, 38 bytes

SELECT QUOTENAME(a)+QUOTENAME(b)FROM i

Input is taken from a pre-existing table \$i\$ with varchar fields \$a\$ and \$b\$, per our IO rules.

Uses QUOTENAME, which surrounds the strings with [] and also escapes any internal brackets. Should map to a unique output.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ Same length on MySQL: SELECT CONCAT(QUOTE(a),QUOTE(b))FROM t Try it online \$\endgroup\$
    – Night2
    Sep 27, 2019 at 18:00
4
\$\begingroup\$

Zsh, 7 bytes

<<<$@:q

Try it online!

Implicitly joins the arguments on spaces. The q modifier tells zsh to quote the arguments, which crucially escapes spaces, ensuring an unescaped space unambiguously separates the two arguments.

(Without q, "a " "b" and "a" " b" would both yield "a b".)

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

MATL, 1 byte

j

The code takes an array of two strings as input, and outputs a string representation of that array.

Try it online!

Explanation

The code simply reads the input as a string, unevaluated.

\$\endgroup\$
2
  • 1
    \$\begingroup\$ Does this really take two strings as input? It seems like this just prints the input whatever it is.Try it online! \$\endgroup\$
    – DJMcMayhem
    Sep 27, 2019 at 17:28
  • 1
    \$\begingroup\$ @DJ It just reads unevaluated input, so it reads anything. Is it a loophole? A more standard approach would be to take the evaluated input as an array and then convert to string representation. But the result would be the same as my code, so I would argue that the distinction is unobservable \$\endgroup\$
    – Luis Mendo
    Sep 27, 2019 at 17:45
3
\$\begingroup\$

Jelly, 2 bytes

ŒṘ

A monadic Link accepting a list of two lists of characters as its argument which yields a single list of characters.

Try it online!

How?

It's a built-in to get Python's string representation, simples.

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

05AB1E, 2 bytes

₁ö

Try it online! Interprets each string as a base-256 integer, then prints the two in the form [1, 2].


05AB1E, 1 byte (unknown validity)

â

Try it online!

Takes the cartesian product of the input with itself. Quotes in the input are not escaped, which could cause confusion. I brute-forced all combinations of up to 12 ", " and "], [" and didn’t find any collision; however, I can’t prove there aren’t any collisions for longer strings. If anybody can come up with a proof or counter-example, I’d highly appreciate it!

The trivial 0-byter fails because of quotes not being escaped: inputs (", ", empty string) and (empty string, ", ") both yield the output ["", "", ""].

The 1-byter º (mirror each input string) also fails because of this: inputs (", "" ,", empty string) and (empty string, " ,"", ") both yield the output ["", "" ,"", "" ,"", ""].

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

C# with 26 bytes (thanks to Lukas Lang, Kevin Cruijssen and Jo King)

a=>b=>$"{a.Length}.{a}{b}"

tio.run lambda

\$\endgroup\$
11
  • 1
    \$\begingroup\$ Please consider using tio.run \$\endgroup\$
    – Ver Nick
    Sep 28, 2019 at 14:49
  • \$\begingroup\$ This still breaks on ("a<>","b") and ("a","<>b") - note that it is impossible to handle all cases if you're just concatenating the inputs, no matter what you put between/around them - you need to modify the strings somehow \$\endgroup\$
    – Lukas Lang
    Sep 28, 2019 at 17:54
  • 1
    \$\begingroup\$ Sorry, still not: ("1","11111111111") and ("11111111111","1") - what does work on the other hand (and is even shorter) is this $"{a.Length}.{a}{b}" - you can always extract a and b from this without any ambiguity (just read until the first . to get the length of a, b is then the rest \$\endgroup\$
    – Lukas Lang
    Sep 28, 2019 at 19:14
  • 1
    \$\begingroup\$ @LukasLang Great. Thanks for the follow ups. \$\endgroup\$
    – Soleil
    Sep 28, 2019 at 19:27
  • 1
    \$\begingroup\$ Many thanks @JoKing ! \$\endgroup\$
    – Soleil
    Oct 2, 2019 at 0:11
2
\$\begingroup\$

Charcoal, 12 bytes

⪫E²⭆⪪S"⪫""λ,

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

 E²             Repeat twice
     S          Input a string
    ⪪ "         Split it on `"`s
   ⭆            Map over each piece and join
       ⪫""λ     Wrap each piece in `"`s
⪫          ,    Join the two results with a `,`
                Implicitly print
\$\endgroup\$
2
\$\begingroup\$

PowerShell, 22 bytes

Many fixes thanks to mazzy

"$($args|% le*)"+$args

Try it online!

Take five, oh my.

\$\endgroup\$
3
  • \$\begingroup\$ "ab" "c" and "a" "bc" both produce the same output. \$\endgroup\$
    – BradC
    Sep 27, 2019 at 20:50
  • \$\begingroup\$ @JoKing Things should be fixed. Hopefully. \$\endgroup\$
    – Veskah
    Sep 28, 2019 at 4:32
  • 1
    \$\begingroup\$ 15 bytes with $OFS? \$\endgroup\$ Sep 28, 2019 at 15:07
2
\$\begingroup\$

R, 4 bytes

dput

Try it online!

A built-in function which returns the string representation of the input (inspired by Jonathan Allan's answer )

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

Wolfram Language (Mathematica), 8 bytes

Compress

Try it online!

\$\endgroup\$
2
  • 1
    \$\begingroup\$ {"Hello, ","World"} and {"Hello",", World"} don't they give the same string? \$\endgroup\$ Sep 27, 2019 at 20:00
  • \$\begingroup\$ @NahuelFouilleul ah, nice catch. Compress it is then \$\endgroup\$
    – att
    Sep 27, 2019 at 21:27
1
\$\begingroup\$

CSS + HTML, 55 + 20 = 75 bytes

Provide the inputs in the HTML after <code> tags. Visually injects letters one by one from each input into the output. When an input is longer than the other one, visual spaces are shown for missing letter(s) of the shorter input. Also one comma is added in HTML to force visual output uniqueness (I hope).

*{position:absolute;letter-spacing:9px}code>code{left:9px
<code>abcdefg<code>hijklmn</code>,

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

C# (Visual C# Interactive Compiler), 5 bytes

Print

Try it online!

\$\endgroup\$
1
  • 1
    \$\begingroup\$ Why the downvote? My solution is perfectly valid \$\endgroup\$
    – Gymhgy
    Sep 28, 2019 at 16:11
1
\$\begingroup\$

Perl 6, 6 3 bytes

&dd

Try it online!

Outputs the object representation to STDERR.

\$\endgroup\$
3
  • \$\begingroup\$ I'm not familiar enough with Perl - how would you input a string containing spaces here? \$\endgroup\$ Sep 28, 2019 at 8:32
  • 2
    \$\begingroup\$ @negativeseven like this \$\endgroup\$
    – Grimmy
    Sep 28, 2019 at 9:17
  • \$\begingroup\$ @negativeseven Yeah sorry, I was just using a shortcut syntax for lists of strings. You can do that in a typical fashion like ["Hello, ", "World!"] \$\endgroup\$
    – Jo King
    Sep 29, 2019 at 2:01
1
\$\begingroup\$

Lua, 27 bytes

print(('%q%q'):format(...))

Try it online!

Full program, take input as arguments.

Inspired by zsh answer, as it also use %q modifier to use internal safe-string engine.

Also, I can think of just

('%q%q'):format

but I'm not sure if this is acceptable answer.

\$\endgroup\$
2
  • \$\begingroup\$ I don't think the second is valid since ('%q%q'):format doesn't result in an object that can, for example, be assigned to a variable. It just causes a syntax error on its own. The colon syntax is just a shortcut for '%q%q'.format('%q%q', ...) and Lua doesn't allow partial application for functions \$\endgroup\$
    – Jo King
    Sep 30, 2019 at 0:15
  • \$\begingroup\$ @JoKing Yeah, you are right, I think. \$\endgroup\$ Sep 30, 2019 at 4:06
1
\$\begingroup\$

sed, 19 bytes

N
s/ /. /g
s/\n/: /

Try it online!

N          # append the second string into the pattern space
s/ /. /g   # prefix all spaces with ".". Now ": " will not occur in the stiring
s/\n/: /   # replace the newline with ": "
\$\endgroup\$
1
\$\begingroup\$

JavaScript (SpiderMonkey), 6 bytes

uneval

Try it online!

Input array of strings, output a single string.

Inspired by Arnauld's JSON.stringify answer.

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

C (gcc), 59 bytes

Thanks to Grimy for the suggestion.

Takes an array of input strings (of which "2" is the correct number for this challenge) and prints their character values, including the trailing NUL. Technically, the %p formatter used by printf is for pointers, but it works fine for displaying hex values of arbitrary integers if you're not picky about how they look!

f(s,t)char**s,*t;{for(;t=*s++;)for(;printf("%p",*t++)^5;);}

Try it online!

\$\endgroup\$
1
  • \$\begingroup\$ Nice! Here’s a 59. \$\endgroup\$
    – Grimmy
    Oct 1, 2019 at 9:25
1
\$\begingroup\$

Brachylog, 0 bytes

Input as an array of 2 strings, output in the format: Z = ["{{string 1 stringified}}","{{string 2 stringified}}"]

Inspired by Arnauld's JSON.stringify answer and Doorknob's empty jq answer

Try it online!

\$\endgroup\$
0
\$\begingroup\$

PHP, 9 bytes

serialize

Try it online!

Input is an array of 2 strings like this: ['abc', 'def']. Uses PHP's serialize to serialize the input into a string.

\$\endgroup\$
0
\$\begingroup\$

Bash, 11 bytes

echo ${@@Q}

Try it online!

${parameter@Q} quotes the parameter for reuse as input. In the case of an array, it quotes each element.

\$\endgroup\$
0
\$\begingroup\$

Ruby, 12 bytes

->*a{a.to_s}

Try it online!

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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