# Element-wise string multiplication

Inspired by this challenge (thanks @cairdcoinheringaahing for the title!), your task is to take two printable ASCII strings and multiply them element-wise with the following rules.

### How does it work?

Given two strings (for example split and isbn) you will first, truncate the longer one such that they have equal length and then determine their ASCII codes:

split -> spli -> [115, 112, 108, 105]
isbn  -> isbn -> [105, 115,  98, 110]


The next step will be to map them to the range [0..94] by subtracting 32 of each code:

[115, 112, 108, 105] -> [83, 80, 76, 73]
[105, 115,  98, 110] -> [73, 83, 66, 78]


Now you will multiply them element-wise modulo 95 (to stay in the printable range):

[83, 80, 76, 73] ⊗ [73, 83, 66, 78] -> [74, 85, 76, 89]


Add 32 to get back to the range [32..126]:

[74, 85, 76, 89] -> [106, 117, 108, 121]


And the final step is to map them back to ASCII characters:

[106, 117, 108, 121] -> "july"


### Rules

• You will write a program/function that implements the described steps on two strings and either prints or returns the resulting string
• The input format is flexible: you can take two strings, a tuple of strings, list of strings etc.
• The input may consist of one or two empty strings
• The input will be characters in the printable range ([32..126])
• The output is either printed to the console or you return a string
• The output is allowed to have trailing whitespaces

### Test cases

"isbn", "split"                  -> "july"
"", ""                           -> ""
"", "I don't matter"             -> ""
"             ", "Me neither :(" -> "             "
"but I do!", "!!!!!!!!!"         -> "but I do!"
'quotes', '""""""'               -> 'ck_iKg'
"wood", "hungry"                 -> "yarn"
"tray", "gzip"                   -> "jazz"
"industry", "bond"               -> "drop"
"public", "toll"                 -> "fall"
"roll", "dublin"                 -> "ball"
"GX!", "GX!"                     -> "!!!"
"4 lll 4", "4 lll 4"             -> "4 lll 4"
"M>>M", "M>>M"                   -> ">MM>"


Note: The quotes are just for readability, in the 6th test case I used ' instead of ".

• Are you allowed to have trailing spaces in your output? Jul 21, 2017 at 15:54
• @EriktheOutgolfer Yes. Sorry, I added that after posting it. Jul 21, 2017 at 15:54
• Can we take an array of arrays of strings? abc, def -> [['a', 'b', 'c'], ['d', 'e', 'f']] Jul 21, 2017 at 16:19
• @totallyhuman I wouldn't say so. Though, if in your language strings are arrays of chars and chars have the same type as strings, then it would be valid I guess. Jul 21, 2017 at 16:23
• Are we allowed to take input as a list of strings? Jul 21, 2017 at 16:44

# PHP, 112 bytes

for($i=0;$i<min(strlen($a=$argv[1]),strlen($b=$argv[2]));$i++)echo chr((ord($a[$i])-32)*(ord($b[$i])-32)%95+32);  • 109 bytes: for($i=0;$i<strlen($a=$argv[1])&&$i<strlen($b=$argv[2]);)echo chr((ord($a[$i])-32)*(ord($b[$i++])-32)%95+32); Also, I'm not entirely sure if replacing && with & might also be possible in PHP, reducing it by another byte to 108. Oct 23, 2017 at 12:45

# JavaScript (ES6), 89 bytes

Javascript and the curse of the lengthy function names ...

Using currying and the fact that charCodeAt returns NaN when called with an invalid position. There can be trailing nulls in the output.

a=>b=>a.replace(/./g,(c,i)=>String.fromCharCode((z=x=>x.charCodeAt(i)-32)(a)*z(b)%95+32))


Test

var f=
a=>b=>a.replace(/./g,(c,i)=>String.fromCharCode((z=x=>x.charCodeAt(i)-32)(a)*z(b)%95+32))

q=x=>'['+x+']'

;[["isbn", "split"],["", ""],["", "I don't matter"],["             ", "Me neither :("],
["but I do!", "!!!!!!!!!"],['quotes', '""""""'],["wood", "hungry"],["tray", "gzip"],
["industry", "bond"],["public", "toll"],["roll", "dublin"],["GX!", "GX!"],
["4 lll 4", "4 lll 4"],["M>>M", "M>>M"]]
.forEach(([a,b])=>console.log(q(a)+' x '+q(b)+' --> '+q(f(a)(b))))

# Vyxal, 16 bytes

øŀC32-ƒ*95%32+Cṅ


Try it Online!

øŀC32-ƒ*95%32+Cṅ  # Example input: ["wood", "hungry"]
øŀ                # Align to left by padding to the right with spaces: ["wood  ", "hungry"]
C               # Character codes: [[119, 111, 111, 100, 32, 32], [104, 117, 110, 103, 114, 121]]
32-            # Subtract 32: [[87, 79, 79, 68, 0, 0], [72, 85, 78, 71, 82, 89]]
ƒ*          # Element-wise multiply both: [6264, 6715, 6162, 4828, 0, 0]
95%       # Modulo 95: [89, 65, 82, 78, 0, 0]
32+    # Add 32: [121, 97, 114, 110, 32, 32]
C   # From character codes: ["y", "a", "r", "n", " ", " "]
ṅ  # Join together: "yarn  "


# Ruby, 88 bytes

->a{c,d=a.map{_1[0,a.map(&:size).min].bytes}
c.map{((_1-32)*(d.shift-32)%95+32).chr}*""}


Attempt This Online!

# Thunno 2B, 12 bytes

Z32-€p95%32+


Try it online!

#### Explanation

Z32-€p95%32+  # Implicit input (converted to ordinals)
Z             # Zip them together (truncate longer one)
32-          # Subtract 32 (vectorised)
€p        # Product of each inner pair
95%     # Modulo by 95 (vectorised)
# Implicit output (converted to string)


# Zsh, 82 bytes

s=
repeat $#1 ((#2))&&s+=${(#)$((32+(#1-32)*(#2-32)%95))}&&1=${1:1} 2=${2:1} <<<$s


Attempt This Online!

The flags needed to emulate zip() added too many characters, so we instead repeat for the length of the first argument, and check ((#2)) to see if we've reached the end of the second argument.

# jq, 62 bytes

map(explode)|transpose|map((.[0]-32)*(.[1]-32)%95?+32)|implode


Attempt This Online!

transpose fills in null for missing elements, we suppress those with ?.