11
\$\begingroup\$

In this challenge you'll be using be distributing a product over sums and differences of numbers, as explained here.

enter image description here

Examples

  Input      |     Output
-------------|-------------
23(12+42)    | (23*12)+(23*42)
9(62-5)      | (9*62)-(9*5)
4(17+8-14)   | (4*17)+(4*8)-(4*14)
15(-5)       | -(15*5)
2(3)         | (2*3)
8(+18)       | +(8*18)
8(-40+18)    | -(8*40)+(8*18)

Specification

The input will be a string of the form n(_), with a single positive unsigned integer n followed by a parenthesized expression _. This expression _ will consist of sums and difference of one of more positive-integer terms separated by + and - signs. The first term may be preceded by a + sign, a - sign, or by no sign.

In the output, the initial number n should be distributed to multiply each of the terms. Each term of a should be left-multiplied by n to produce the parenthesized expression (n*a), and these new terms should be combined with + and - signs in exactly the same way as the original terms were.

Invalid Inputs

These are examples of inputs you don't have to handle.

3(5 plus 3)
6(5 13)
(5+8)(6+6)
(5+3)8

Winning

This is , so shortest code in bytes wins.

\$\endgroup\$
  • \$\begingroup\$ It occurs to me that regex is really well-suited for this problem. If you're not OK with reg-ex solutions, you could ban it, though people might be working on it already. \$\endgroup\$ – xnor Aug 23 '15 at 18:38
  • \$\begingroup\$ Are libraries allowed? \$\endgroup\$ – orlp Aug 23 '15 at 18:47
  • \$\begingroup\$ @orlp To a certain extent which was discussed on meta. \$\endgroup\$ – Downgoat Aug 23 '15 at 18:51
  • \$\begingroup\$ Interesting case: 8(-40+18) \$\endgroup\$ – BrainSteel Aug 23 '15 at 19:48

15 Answers 15

2
\$\begingroup\$

Pip, 28 bytes

DQaUnxWa^'(xR`\d+`'(.n.`*&)`

Explanation:

                              a is first cmdline arg (implicit)
DQa                           Remove (DeQueue) the closing paren from a
   UnxWa^'(                   Unify n and x with a split on open paren--Python equivalent
                                n,x=a.split("(")
                              n is thus the number to be distributed, and x is the
                                addition/subtraction expression
           xR                 In x, replace...
             `\d+`            ... regex matching numbers...
                  '(.n.`*&)`  ... with the replacement pattern (n*&), where n is the
                                appropriate number and & substitutes the complete match
                              Print result (implicit)

Pip's Pattern objects mostly follow Python regex syntax, but the & replacement pattern is borrowed from sed.

Read more about Pip at the Github repository

\$\endgroup\$
9
+50
\$\begingroup\$

JavaScript 65 bytes

s=>(q=s.split(/[()]/))[1].replace(/(\D?)(\d+)/g,`$1(${q[0]}*$2)`)

This will take the input. Get the + or -, then the digits, then replace it in the correct order.

Explanation

s=>   // Function with argument "s"
  (q= // Set q to...
    s.split(/[()]/) // Splits on parenthesis, returns array
  )
  [1] // Gets second match or text inside brackets
  .replace(/ // Replaces string 
     (\D?)  // Try to match a non-digit, the +-/* (group 1)
     (\d+)  // Then match one or more digits (group 2)
  /,
      // $1 is group 1 and $2 is group 2 q[0] is the text before the parenthesis 
  `$1(${q[0]}*$2)`
  ) 

Usage

This only works in Firefox and Safari Nightly maybe Edge? because it uses ES6 features. You can run it by:

var t=s=>(q=s.split(/[()]/))[1].replace(/(\D?)(\d+)/g,`$1(${q[0]}*$2)`)

t("5(-6+7+3-8+9)"); // -(5*6)+(5*7)+(5*3)-(5*8)+(5*9)
\$\endgroup\$
  • \$\begingroup\$ (.?)(\d+) is broken. This fails on 23(12+42), producing 1(23*2)+(23*42). \$\endgroup\$ – orlp Aug 23 '15 at 20:45
  • \$\begingroup\$ @orlp I have fixed that \$\endgroup\$ – user42090 Aug 23 '15 at 23:08
  • \$\begingroup\$ This code will only work in Firefox b/c of the arrow function, but that's fine \$\endgroup\$ – MayorMonty Aug 24 '15 at 0:28
  • \$\begingroup\$ @SpeedyNinja It also works in Edge. For Chrome/Opera you need to enable "experimental JavaScript features". \$\endgroup\$ – rink.attendant.6 Aug 24 '15 at 3:38
  • \$\begingroup\$ \D? could be used instead of [+-]? \$\endgroup\$ – edc65 Aug 24 '15 at 7:45
6
\$\begingroup\$

Python 2.7, 110 108 Bytes

import re
p=re.findall('([+-]?)(\d+)',raw_input())
print"".join("%s(%s*%s)"%(e[0],p[0][1],e[1])for e in p[1:])

The program takes input from stdin, searches for matches against - ([+-]?)(\d+) regex and creates the output string.
Testing it -

<< 23(12+42)
>> (23*12)+(23*42)

<< 9(62-5)
>> (9*62)-(9*5)

<< 4(17+8-14)
>> (4*17)+(4*8)-(4*14)

<< 15(-5)
>> -(15*5)

<< 2(3)
>> (2*3)

<< 8(+18)
>> +(8*18)

<< 8(-40+18)
>> -(8*40)+(8*18)
\$\endgroup\$
4
\$\begingroup\$

Retina, 40 bytes

+`(\d+)\((\D)?(\d+)
$2($1*$3)$1(
\d+..$
<empty line>

Each line should go to its own file but you can run the code as one file with the -s flag. E.g.:

>echo -n "8(-40+18)"|retina -s distributing_numbers
-(8*40)+(8*18)

The first two lines push the multiplier next to every number in the expected form:

8(-40+18)
-(8*40)8(+18)
-(8*40)+(8*18)8()

The last two lines remove the unnecessary trailing part:

-(8*40)+(8*18)8()
-(8*40)+(8*18)
\$\endgroup\$
3
\$\begingroup\$

sed, 105 bytes

Just wanted to see if this can be done with sed.
Maybe a bit old school, but it works.

$ cat distnum.sed
s@\([0-9]*\)(\([0-9]*\)\([+-]*\)\([0-9]*\)\([+-]*\)\([0-9]*\))@(\1*\2)\3(\1*\4)\5(\1*\6)@
s@([0-9]*\*)@@g

$ cat distnum.txt
23(12+42)
9(62-5)
4(17+8-14)
15(-5)
2(3)
8(+18)
8(-40+18)

$ sed -f distnum.sed distnum.txt
(23*12)+(23*42)
(9*62)-(9*5)
(4*17)+(4*8)-(4*14)
-(15*5)
(2*3)
+(8*18)
-(8*40)+(8*18)
\$\endgroup\$
2
\$\begingroup\$

rs, 77 bytes

$$d=(?<!\))([+-]?)(\d+)
+$d\($d([+-])/\3(\1\2*\4)\5\1\2(
$d\($d\)/\3(\1\2*\4)

Live demo and all test cases.

This is the first time rs's macros have actually been used!

\$\endgroup\$
2
\$\begingroup\$

REGXY, 45 bytes

Uses REGXY, a regex substitution based language.

/(\d+)\((\D)?(\d+)/\2(\1*\3)\1(/
//
/\d+\(.//
\$\endgroup\$
  • \$\begingroup\$ How does the // work? I suppose it loops to the top until the string changes but I can't find in the esolang page why. \$\endgroup\$ – randomra Sep 6 '15 at 8:35
  • \$\begingroup\$ It's a bit of a cheeky abuse of the vagueness in the language spec, but I've explained it here: codegolf.stackexchange.com/questions/52946/… \$\endgroup\$ – Jarmex Sep 6 '15 at 19:18
  • 1
    \$\begingroup\$ I still don't get why doesn't the // create an infinite loop as nothing will always match so we always jump back to the first line. \$\endgroup\$ – randomra Sep 6 '15 at 21:29
  • \$\begingroup\$ Y'know what? I actually have no idea why. You're absolutely right, thinking about it now it makes no logical sense, but it definitely compiles and runs in the provided interpreter. Even looking at the compiled Perl it generates confuses me, because it looks even clearer that it should be an infinite loop: pastebin.com/9q7M0tpZ \$\endgroup\$ – Jarmex Sep 6 '15 at 22:09
2
\$\begingroup\$

Perl, 36 bytes

35 bytes code + 1 byte command line

($a,$_)=split/[()]/;s/\d+/($a*$&)/g

Usage:

echo "4(17+8-14)" | perl -p entry.pl
\$\endgroup\$
1
\$\begingroup\$

Pyth, 39 38 bytes

A terrible regex solution:

P:eJcz\("([+-]?)(\d+)"X"\\1(_*\\2)"3hJ
\$\endgroup\$
  • \$\begingroup\$ I can't seem to get this to run in the online interpreter. \$\endgroup\$ – BrainSteel Aug 23 '15 at 19:41
  • \$\begingroup\$ @BrainSteel It works in the offline interpreter, it seems to be a problem with heroku. \$\endgroup\$ – orlp Aug 23 '15 at 20:18
  • \$\begingroup\$ @orlp It's not a problem with heroku. Dynamic imports are disabled in safe mode, to reduce the likelihood of a hack, and the re module does a dynamic import. So re can't be used in safe mode, including online. \$\endgroup\$ – isaacg Aug 24 '15 at 19:51
1
\$\begingroup\$

Ruby, 94 bytes

gets.scan(/(\d+)\(([[-+]?\d+]+)/){|a,b|b.scan(/([-+]?)(\d+)/).map{|c,d|$><<"#{c}(#{a}*#{d})"}}
\$\endgroup\$
1
\$\begingroup\$

CJam, 50 bytes

l__'(#_@<'*+@@)>);'+/'-f/\ff{1$'(@@++')+L?}'-f*'+*

Try it online

CJam does not have regex support, or anything beyond string searching and splitting that is very convenient for parsing expressions. So there's some labor involved here.

Explanation:

l__   Get input and push 2 copies for splitting.
'(#   Find index of '(.
_     Copy index, will be used twice.
@<    Get one copy of input to top, and slice to get first multiplier.
'*+   Append '* to first multiplier.
@@    Get another copy of input and '( index to top.
)>    Increment and slice to get everything after '(.
);    Remove trailing ').
'+/   Split at '+.
'-f/  Split each part at '-.
\     Swap first multiplier to top.
ff{   Apply block to nested list of second multipliers.
  1$    Copy term. Will use this copy as condition to skip empty second multipliers
        that result from unary + or -.
  '(    Opening parentheses.
  @@    Get first and second multiplier to top.
  ++    Concatenate it all.
  ')+   Concatenate closing parentheses.
  L     Push empty string for case where term is skipped.
  ?     Ternary if to pick term or empty string.
}     End of loop over list of second multipliers.
'-f*  Join sub-lists with '-.
'+*   Join list with '+.
\$\endgroup\$
1
\$\begingroup\$

gawk - 60 58

$0=gensub(/(.*\()?(+|-)?([0-9]+))?/,"\\2("$0+0"*\\3)","G")

Phew... haven't worked with regexp in quite a while.

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

Perl 5, 70 60 55 44 Bytes + 1 penalty

A perl solution that only uses split and 1 regular expression.
Also calculates the longer inputs.

($a,$_)=split/[()]/;s/(\D?)(\d+)/$1($a*$2)/g

Test

$ echo "8(9-10+11-12+13-14)"|perl -p distnums.pl   
(8*9)-(8*10)+(8*11)-(8*12)+(8*13)-(8*14)

A version that takes a parameter

($a,$_)=split/[()]/,pop;s/(\D?)(\d+)/$1($a*$2)/g;print

A version that only uses regular expressions.

s/(\d+)\((.*)\)/$2:$1/;s/(\D?)(\d+)(?=.*:(\d+)).*?/$1($3*$2)/g;s/:.*//

This one works via a capture group within a positive lookahead and lazy matching. Probably would have used a positive lookbehind if Perl 5 supported it, but alas. Took me a while to figure out that this kinda thing is possible with regex.

\$\endgroup\$
  • 1
    \$\begingroup\$ Hey Luk, You might be able to save some chars using -p command line option (I think this is +1 char vs 9 for ,<> and ;print) as split will work on $_ by default (which will be whatever is in <>) and print is included in the loop too! Hope that helps! \$\endgroup\$ – Dom Hastings Sep 2 '15 at 16:32
  • 1
    \$\begingroup\$ Thanks! It helped. The -p option simply didn't cross my mind. Probably since it's something that's rarely used outside a golfing context. Why do you think it's +1 char? This challenge doesn't mention anything about a penalties for using switches. \$\endgroup\$ – LukStorms Sep 2 '15 at 19:09
  • \$\begingroup\$ I can't find the post now, but this meta post mentions scoring for Perl's flags. \$\endgroup\$ – Dom Hastings Sep 2 '15 at 19:18
  • 1
    \$\begingroup\$ My bad, looks like I came up and posted a very similar solution to you, which is effectively just a slightly more golfed version of yours! Basically you don't even need to capture the [+-] because you leave them intact in the substitution anyway: codegolf.stackexchange.com/a/57117/26977 \$\endgroup\$ – Jarmex Sep 6 '15 at 19:22
  • \$\begingroup\$ That's cool. Because of you, Perl beats even the Pyth/Cjam solutions in this challenge. I shouldn't have cared about the invalid inputs anyway after that split removed the brackets. \$\endgroup\$ – LukStorms Sep 6 '15 at 20:11
1
\$\begingroup\$

Retina, 50 51 43 bytes

I think this may be my first Retina program. If not, it's my first Retina program that's this complex (not that complex, really.) Each line goes in its own file.

+`(\d+)\((\D?)(\d+)
$1($'$2($1*$3)
.+?\)
$'

I didn't actually test this with Retina, I tested it using a regex-replace tester multiple times, but it should work.

Description for first example:

Since there are an even number of files, Retina uses replace mode. The first replace (first two files) removes a number to be distributed and adds that distribution pair (23*12) to the end, giving 23(+42)(23*12). +` at the start tells Retina to repeatedly replace until the pattern doesn't match, and since this is matched again, the pattern replaces this with 23()(23*12)+(23*42). This doesn't match anymore, so the next 2 files are used for the next replace. This time, it merely removes the 23(). This works nicely: since products are appended to the end, I don't have to do anything weird if a number doesn't have a sign, since the only one that can be without a sign is the first number.

EDIT: $' in replacement represents the rest of the string after the match, so I can removing the trailing (.*)s.

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

k, 98 bytes

Not very golfed.

{,/(*x){(s#y),("*"/:(x;(s:(*y)in"+-")_y))/:$"()"}/:1_x@:&~~#:'x:((0,&~x in .Q.n)_x){x_'x?'y}/"()"}

Split on non-digit, remove parens, remove empty strings, then holding x constant as the first string, combine with * with each remaining string y, parenthesize, and move sign to the beginning if present; flatten output into a single string.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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