# 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 '17 at 15:54
• @EriktheOutgolfer Yes. Sorry, I added that after posting it. Jul 21 '17 at 15:54
• Can we take an array of arrays of strings? abc, def -> [['a', 'b', 'c'], ['d', 'e', 'f']] Jul 21 '17 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 '17 at 16:23
• Are we allowed to take input as a list of strings? Jul 21 '17 at 16:44

# MATL, 12 bytes

c32-p95\32+c


Try it online!

### Explanation

c      % Implicitly input cell array of 2 strings. Convert to 2-row char matrix.
% This pads the shorter string with spaces
32-    % Subtract 32, element-wise. Each char is interpreted as its ASCII code.
% Note that padding spaces will give 0.
p      % Product of each column. Since (padding) spaces have been mapped to 0, the
% product effectively eliminates those colums. So the effect is the same as
% if string length had been limited by the shorter one
95\    % Modulo 95, element-wise
c      % Convert to char. Implicitly display

• Clever way of managing the string length difference. Jul 21 '17 at 16:55

# Jelly, 15 12 bytes

z⁶O_32P€‘ịØṖ


Try it online!

-3 thanks to Jonathan Allan.

• Sneaky abuse of trailing whitespace. ;) Jul 21 '17 at 16:20
• @Dennis Well it's in the rules, why not abuse it? Jul 21 '17 at 16:21
• I believe you can save 3 bytes by using the niladic atom for printable characters, ØṖ, with z⁶O_32P€‘ịØṖ - you'd best double check that the arithmetic works though. Jul 21 '17 at 18:34
• @JonathanAllan Of course. Jul 21 '17 at 18:45

# Python 3, 8074 71 bytes

lambda*t:''.join(map(lambda x,y:chr((ord(x)-32)*(ord(y)-32)%95+32),*t))


Thanks to @shooqie for golfing off 3 bytes!

Try it online!

• 71 if you take (s, t) as a tuple: lambda t:''.join(map(lambda x,y:chr((ord(x)-32)*(ord(y)-32)%95+32),*t)) Jul 21 '17 at 16:30

# Python 2, 75 70 bytes

-3 bytes thanks to Dennis' suggestion of shooqie's suggestion. -2 bytes thanks to Zacharý's suggestion.

lambda*l:''.join(chr((ord(i)-32)*(ord(j)-32)%95+32)for i,j in zip(*l))


Try it online!

• Same trick that was suggested on my answer: lambda*t:''.join(chr(((ord(i)-32)*(ord(j)-32))%95+32)for i,j in zip(*t)) Jul 21 '17 at 16:36
• And same one that I suggested a lot: ((ord(i)-32)*(ord(j)-32))%95+32 => (ord(i)-32)*(ord(j)-32)%95+32 ... Jul 21 '17 at 16:38
• o_o beating Dennis. +1 Jul 21 '17 at 16:43
• Eh, not really, I just changed to a list comprehension instead of using map. I was just slightly late. Jul 21 '17 at 16:44

zipWith(\a b->toEnum$f a*f bmod95+32) f=(-32+).fromEnum  Try it online! First line is an anonymous function taking two arguments. This a straight forward implementation of the algorithm: zipWith takes both strings and applies a given function to the pairs of characters. It handles the truncation and also works for empty strings. fromEnum and toEnum are alternatives to ord and chr to switch between characters and their ASCII values which do not need a lengthy import. Edit: -3 bytes thanks to Bruce Forte. • You can save 3 bytes by pulling out -32 and saving those parenthesis, see here. Jul 21 '17 at 18:18 ## C++, 331291282270 268 bytes, Version 2 = 178176150 148 bytes Original Version : #include<string> #include<algorithm> #define L length() #define S std::string S m(S a,S b){S c;int m=a.L<b.L?a.L:b.L;auto l=[m](S&s){s=s.substr(0,m);std::for_each(s.begin(),s.end(),[](char&c){c-=32;});};l(a);l(b);for(int i=0;i<m;++i){c+=a[i]*b[i]%95+32;}return c;}  -40 bytes thanks to Bruce Forte -39 bytes thanks to Zacharý Version 2, inspired by other people's answers #include<string> #define L length() using S=std::string;S m(S a,S b){S c;for(int i=0;i<(a.L<b.L?a.L:b.L);++i)c+=(a[i]-32)*(b[i]-32)%95+32;return c;}  If the first version uses a lambda, it's because i wanted to test C++11 std::async function i just learnt before, so i kept it for no reasons... More readable version : #include<iostream> #include<string> #include<algorithm> using namespace std; #define L length() #define S string //Function code for the original version S m(S a,S b) { S c; int m = a.L < b.L ? a.L : b.L; auto l=[m](S&s){ s = s.substr(0, m); for_each(s.begin(),s.end(),[](char&c){ c -= 32; }); }; l(a); l(b); for(int i=0;i<m;++i) { c += a[i] * b[i] % 95 + 32; } return c; } //Code for the version 2 S m2(S a,S b) { S c; for(int i = 0; i < (a.L < b.L ? a.L : b.L); ++i) { c += (a[i] - 32) * (b[i] - 32) % 95 + 32; } return c; } int main() { string a, b, c; getline(cin, a); getline(cin, b); c = m(a, b); cout << c; }  • Welcome to PPCG! Jul 21 '17 at 19:56 • Welcome to the site! Thanks for your answer, I appreciate it. I have no experience in golfing with C++, but here you'll find some tips. Enjoy your time here! Jul 21 '17 at 20:09 • Also I'm pretty sure you can just submit a function, like this. Jul 21 '17 at 20:10 • Can't you remove the spaces here: #include <string>=>#include<string> and #include <algorithm>=>#include<algorithm>? Jul 21 '17 at 21:54 • In addition you should be able to create a macro equivalent to string and use it accordingly. Jul 21 '17 at 22:00 # Dyalog APL, 36343325 24 bytes {⎕UCS 32+95|×⌿32-⎕UCS↑⍵}  Try it online (TryAPL)! Try it online (TIO)! Input is a list of strings, and has trailing whitespace. Here's how it works: {⎕UCS 32+95|×⌿32-⎕UCS↑⍵} ↑⍵ - the input as a 2d array ⎕UCS - codepoints 32- - subtract 32 ×⌿ - element wise product reduction ([a,b]=>a×b) 95| - Modulo 95 32+ - Add 32 ⎕UCS - Unicode characters  • I didn't get the interface of tryapl.org, so here's a TIO for those that want to try it. Jul 21 '17 at 16:18 • There, I put both in there. Jul 21 '17 at 16:23 # FSharp 275 bytes let f (p : string, q : string) = let l = if p.Length < q.Length then p.Length else q.Length p.Substring(0,l).ToCharArray() |> Array.mapi (fun i x -> (((int(x) - 32) * (int(q.[i]) - 32)) % 95) + 32) |> Array.map (fun x -> char(x).ToString()) |> Array.fold(+) ""  • Welcome to PPCG! Jul 24 '17 at 11:23 • 169 bytes Jul 26 '17 at 23:03 • 127 bytes Jul 27 '17 at 1:09 • 126 bytes Jul 27 '17 at 1:33 • 124 bytes Jul 27 '17 at 1:41 # CJam, 23 bytes {z{2' e]' f-:*95%' +}%}  Try it online! # C# (.NET Core),100 96 95 bytes (l,n)=>{for(int i=0;i<l.Length&i<n.Length;)Console.Write((char)((l[i]-32)*(n[i++]-32)%95+32));}  Try it online! -4 bytes thanks to @Zacharý -1 byte by moving the increment Uses a lambda and abuses the fact that characters are basically ints. • Can you use (l[i]-32)*(n[i]-32)%95+32? Jul 21 '17 at 16:12 • Why yes, I can. Thanks! Jul 21 '17 at 16:14 • You need to fully qualify the Console and you can use currying to save a byte. Compile to a Action<string, Action<string>> like l=>n=> and call like ("word")("string") Jul 24 '17 at 7:57 # Mathematica, 114 bytes (a=Min@StringLength[x={##}];FromCharacterCode[Mod[Times@@(#-32&/@ToCharacterCode/@(StringTake[#,a]&/@x)),95]+32])&  input ["public","toll"] • Is there a way to try it online? Jul 21 '17 at 16:30 • of course, go to sandbox.open.wolframcloud.com/app/objects paste the code, paste input at the end, press shift+enter Jul 21 '17 at 16:36 • what "8 chars"? Jul 21 '17 at 16:45 • Sorry for the confusion! The message "Thanks!" would have been too short to post just like this, it needed 8 chars more. Jul 21 '17 at 16:47 • ok.................................... Jul 21 '17 at 16:48 # Stacked, 52 bytes [,:$#'"!MIN$take"![CS#.toarr]"!32-prod 95%32+#:''#]  Try it online! Function that takes two arguments from the stack. ## Explanation [,:$#'"!MIN$take"![CS#.toarr]"!32-prod 95%32+#:''#]  Let's look at the first part, assuming the top two items are 'split' and 'isbn': ,:$#'"!MIN$take"! stack: ('split' 'isbn') , pair top two: (('split' 'isbn')) : duplicate: (('split' 'isbn') ('split' 'isbn'))$#'                  length function literal:    (('split' 'isbn') ('split' 'isbn') $#') "! execute on each: (('split' 'isbn') (5 4)) MIN obtain the minimum: (('split' 'isbn') 4)$take         "take" function literal:    (('split' 'isbn') 4 $take) (e.g. 'asdf' 2 take is 'as') "! vectorized binary each: (('spli' 'isbn'))  This part performs the cropping. Then: [CS#.toarr]"! stack: (('spli' 'isbn')) [ ]"! perform the inside on each string string 'spli': CS convert to a character string:$'spli'
#.             vectorized "ord":                 (115 112 108 105)
toarr        convert to array:                 (115 112 108 105)
(needed for empty string, since $'' #. == $'' not ()


Then, the last part:

32-prod 95%32+#:''#  stack: (((115 112 108 105) (105 115  98 110)))
32-                   subtract 32 from each character code:   (((83 80 76 73) (73 83 66 78)))
prod               reduce multiplication over the array:   ((6059 6640 5016 5694))
95%           modulus 95:                             ((74 85 76 89))
32+        add 32:                                 ((106 117 108 121))
#:      convert to characters:                  (('j' 'u' 'l' 'y'))
''#  join:                                   ('july')


# R, 88 bytes

function(r,s,u=utf8ToInt)intToUtf8((((u(r)-32)*(u(s)-32))%%95+32)[0:min(nchar(c(r,s)))])


anonymous function; takes input as two strings; third argument is just to ensure this is a one line function and save some bytes.

The TIO link below returns an array with entries named with the first input.

Try all test cases!

# Perl 5, 65 bytes

64 bytes of code + -p flag.

$n=reverse<>;s/./($_=chop$n)&&chr 32+(-32+ord$&)*(-32+ord)%95/ge


Try it online!

# D, 113 bytes

T m(T)(T a,T b){T c;for(int i;i<(a.length<b.length?a.length:b.length);++i)c~=(a[i]-32)*(b[i]-32)%95+32;return c;}


This is a port of HatsuPointerKun's C++ solution, don't forget to upvote them!

Try it online!

# 05AB1E, 16 15 bytes

.BÇ32-*₃%32+çJ


Try it online!

-1 for Emigna pointing out ₃ pushes 95.

                 # ['hi', 'you']
.B               # [['hi ', 'you']]
Ç              # [[[104, 105, 32], [121, 111, 117]]]
32-           # [[[72, 73, 0], [89, 79, 85]]]
# [[72, 73, 0], [89, 79, 85]]
*         # [[6408, 5767, 0]]
₃%       # [[43, 67, 0]]
32+    # [[75, 99, 32]]
ç   # [['K', 'c', ' ']]
J  # ['Kc ']


.BÇ32-*95%žQsèJ


is another.

• ₃ saves a byte. Too bad about the empty string input. Otherwise ø would save a few more. Mar 29 '18 at 8:25

# Java 8, 12711597 95 bytes

a->b->{for(int i=0;i<a.length&i<b.length;System.out.printf("%c",(a[i]-32)*(b[i++]-32)%95+32));}


Explanation:

Try it here.

a->b->{                       // Method with 2 char-array parameters and no return-type
for(int i=0;                //  Index-integer, starting at 0
i<a.length&i<b.length;  //  Loop over both arrays up to the smallest of the two
System.out.printf("%c",   //   Print, as character:
(a[i]-32)               //    Current char of a minus 32
*(b[i++]-32)            //    multiplied with current char of b minus 32
%95                     //    Take modulo-95 of that multiplied result
+32));}                 //    And add 32 again


# C#, 166 bytes

using System.Linq;s=>t=>{int e=s.Length,n=t.Length,l=e>n?n:e;return string.Concat(s.Substring(0,l).Select((c,i)=>(char)((((c-32)*(t.Substring(0,l)[i]-32))%95)+32)));}


I'm sure there's a lot of golfing to be done but I don't have time right now.

Try it online!

Full/Formatted Version:

using System;
using System.Linq;

class P
{
static void Main()
{
Func<string, Func<string, string>> f = s => t =>
{
int e = s.Length, n = t.Length, l = e > n ? n : e;

return string.Concat(s.Substring(0, l).Select((c, i) => (char)((((c - 32) * (t.Substring(0, l)[i] - 32)) % 95) + 32)));
};

Console.WriteLine(string.Concat(f("split")("isbn")));

}
}

• I think (((c-32)*(t.Substring(0,l)[i]-32))%95)+32) can be ((c-32)*(t.Substring(0,l)[i]-32)%95+32) (might have screwed up the parens there ... it's looking like lisp!) Jul 21 '17 at 16:11

# Common Lisp, 99 bytes

(lambda(a b)(map'string(lambda(x y)(code-char(+(mod(*(-(#1=char-code x)32)(-(#1#y)32))95)32)))a b))


Try it online!

# Japt, 24 bytes

¬íVq)®®©c -HÃ×u95 +H dÃq


Returns a string with trailing null-chars (\u0000) when the first input is longer than the second.

Try it online! with the -Q flag to show formatted output, including the null-chars.

Run all the test cases using my WIP CodePen.

# Python 2, 95 73 bytes

• Thanks @Zacharý for 4 bytes: unwanted brackets removed
lambda x,y:''.join(chr((ord(i)-32)*(ord(j)-32)%95+32)for i,j in zip(x,y))


Try it online!

• Goodness gracious ... learn to use order of operations! (((ord(x[i])-32)*(ord(y[i])-32))%95)+32 => (ord(x[i])-32)*(ord(y[i])-32)%95+32 Jul 21 '17 at 16:25

# Charcoal, 30 bytes

Ｆ⌊⟦ＬθＬη⟧℅⁺³²﹪×⁻³²℅§θι⁻³²℅§ηι⁹⁵


Try it online! Link is to verbose version of code. I actually wrote the calcualation as (32 - ord(q)) * (32 - ord(h)) because it avoids consecutive numeric literals but I guess I could have just written (ord(q) - ord(" ")) * (ord(h) - ord(" ")) instead.

# Perl 5, 95 bytes

@a=<>=~/(.)/g;@b=<>=~/(.)/g;$#a=$#b if@a>@b;print chr 32+(-32+ord$_)*(-32+ord$b[$i++])%95 for@a  Try it online! Explanation: @a=<>=~/(.)/g;@b=<>=~/(.)/g; # Split the strings into 2 arrays$#a=$#b if@a>@b; # Truncate the first if longer than the second print chr 32+(-32+ord$_)*(-32+ord$b[$i++])%95 for@a  # Multiply each character

• I think you're not correctly truncating the result to the length of the smaller string (see here).
Jul 27 '17 at 8:42
• You're right. Fixed it at a cost of many bytes Jul 27 '17 at 16:35

# Pip, 19 bytes

(PA$* *(PA@?Zg)%95)  Takes the strings as command-line arguments. Try it online! ### Explanation (PA$* *(PA@?Zg)%95)
g is list of args; PA is string of all printable ASCII characters
Zg       Zip items of g together: result is list of pairs of characters
PA@?         Find index of each character in PA
(      )      (Parentheses to get correct operator precedence)
$* * Map (fold on *) to the list: multiplies each pair of numbers %95 Take list items mod 95 (PA ) Use those numbers to index into PA again Print the resulting list of chars, concatenated together (implicit)  # Factor, 45 [ [ [ 32 - ] bi@ * 95 mod 32 + ] "" 2map-as ]  It's a quotation (lambda), call it with two strings on the stack, leaves the new string on the stack. As a word: : s* ( s1 s2 -- ps ) [ [ 32 - ] bi@ * 95 mod 32 + ] "" 2map-as ; "M>>M" "M>>M" s* ! => ">MM>" dup s* ! => "M>>M" dup s* ! => ">MM>" ...  # K (oK), 26 bytes Solution: c$32+95!*/-32+(&/#:'x)$x:  Try it online! Example: c$32+95!*/-32+(&/#:'x)$x:("split";"isbn") "july"  Explanation: Evaluation is performed right-to-left: c$32+95!*/-32+(&/#:'x)$x: / the solution x: / assign input to variable x$   / pad right to length on left
(  #:'x)    / count each x (return length of each char list in list)
&/         / min-over, get the minimum of these counts
-32+            / subtract 32, this automagically converts chars -> ints
*/                / multiply-over, product of the two lists
95!                  / modulo 95
32+                     / add 32 back again
c$/ convert to character array  # Kotlin, 65 bytes {zip(it){a,b->(a-' ')*(b-' ')%95+32}.fold(""){s,i->s+i.toChar()}}  Try it online! # Factor, 39 bytes [ [ [ 32 - ] bi@ * 95 mod 32 + ] 2map ]  Try it online! ## Explanation: This is a quotation (anonymous function) that takes two strings from the data stack and leaves one string on the data stack. In Factor, strings are just sequences of unicode code points and can be manipulated like any other sequence. • Assuming a data stack that looks like "split" "isbn" when this function is called... • [ [ 32 - ] bi@ * 95 mod 32 + ] push a quotation to the data stack (to be used later by 2map) "split" "isbn" [ [ 32 - ] bi@ * 95 mod 32 + ] • 2map map over two sequences, combining them into one sequence with the given quotation which has stack effect ( x x -- x ). • At the beginning of the first iteration of 2map, the data stack looks like this: 115 105 • [ 32 - ] push a quotation to the data stack to be used later by the word bi@. 115 105 [ 32 - ] • bi@ apply a quotation to the object on top of the data stack and the second-top object on the data stack 83 73 • * multiply top two objects on the data stack 6059 • 95 push 95 to the data stack 6059 95 • mod reduce NOS (next on stack) modulo TOS (top of stack) 74 • 32 push 32 to the data stack 74 32 • + add top two objects on the data stack 106 • So, at the end of the quotation to 2map, we are left with 106, which is the code point for 'j', which is the first element of the output sequence. The quotation given to 2map will be run on each pair of elements until one of the two sequences no longer has any elements, meaning the output sequence will have the same size as the shorter of the two input sequences. # PHP, 112 bytes for($i=0;$i<min(strlen($a=$argv),strlen($b=$argv));$i++)echo chr((ord($a[$i])-32)*(ord($b[$i])-32)%95+32);

• 109 bytes: for($i=0;$i<strlen($a=$argv)&&$i<strlen($b=$argv);)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 '17 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))))`