35
\$\begingroup\$

Given a nonempty list of nonnegative integers, consider rewriting it as an arithmetic problem where:

  • A plus sign (+) is inserted between pairs of numbers that increase from left to right (a.k.a. from the start of the list to the end).
  • A minus sign (-) is inserted between pairs of numbers that decrease from left to right.
  • A multiplication sign (*) is inserted between pairs of numbers that are equal.

Said another way: any sublist a,b becomes a+b if a<b, a-b if a>b, and a*b if a==b.

For example, the list

[12, 0, 7, 7, 29, 10, 2, 2, 1]

would become the expression

12 - 0 + 7*7 + 29 - 10 - 2*2 - 1

which evaluates to 75.

Write a program or function that takes in such a list and evaluates it, printing or returning the result.

  • Order of operations matters. Multiplications should be done before any addition or subtraction.
  • If the input list has one number, that should be what it evaluates to. e.g. [64] should give 64.
  • Use of eval or exec or similar constructs is allowed.

Here are some additional examples:

[list]
expression
value

[0]
0
0

[1]
1
1

[78557] 
78557
78557

[0,0]
0*0
0

[1,1]
1*1
1

[2,2]
2*2
4

[0,1]
0+1
1

[1,0]
1-0
1

[1,2]
1+2
3

[2,1]
2-1
1

[15,4,4]
15-4*4
-1

[9,8,1]
9-8-1
0

[4,2,2,4]
4-2*2+4
4

[10,9,9,12]
10-9*9+12
-59

[1,1,2,2,3,3]
1*1+2*2+3*3
14

[5,5,4,4,3,3]
5*5-4*4-3*3
0

[3,1,4,1,5,9,2,6,5,3,5,9]
3-1+4-1+5+9-2+6-5-3+5+9
29

[7637,388,389,388,387,12,0,0,34,35,35,27,27,2]
7637-388+389-388-387-12-0*0+34+35*35-27*27-2
7379

The shortest code in bytes wins. Tiebreaker is earlier answer.

\$\endgroup\$
  • 5
    \$\begingroup\$ Regarding "order of operations matters" it might be good to state explicitly that addition and subtraction are left-associative and have the same precedence. \$\endgroup\$ – Martin Ender Jun 12 '16 at 8:15

22 Answers 22

15
\$\begingroup\$

Python 2, 63 bytes

p=s='print-'
for x in input():s+='*+-'[cmp(x,p)]+`x`;p=x
exec s

Constructs and evals the expression string. The arithmetic symbol is chosen by comparing the previous number p to the current one x. The symbol is appended followed by the current number.

The first number is handled with a clever trick from Sp3000. The initial value of p is set to a string, which is bigger than any number and therefore causes a - before the first number. But, s is initialized to print- at the same time that makes the result start with print-- (thanks to xsot for saving 2 bytes by initializing with print.)

\$\endgroup\$
  • \$\begingroup\$ I think you can move print into the string and use exec instead of eval. \$\endgroup\$ – xsot Jun 12 '16 at 13:20
13
\$\begingroup\$

Pyth, 31 26 19 17 16 15 bytes

Expressions with * won't evaluate online, but they would theoretically work.

2 bytes thanks to Maltysen.

vsm+@"*-+"._-~k

Test suite (with evaluation).

The other cases (without evaluation).

History

  • 31 bytes: M+G@"*-+"->GH<GHv+sgMC,JsMQtJ\x60e
  • 26 bytes: M+G@"*-+"->GH<GHv+sgVQtQ\x60e
  • 19 bytes: vtssVm@"*-+"->Zd<~Z
  • 17 bytes: vtssVm@"*-+"._-~Z
  • 16 bytes: vssVm@"*-+"._-~k
  • 15 bytes: vsm+@"*-+"._-~k
\$\endgroup\$
  • \$\begingroup\$ Why won't multiplication work online? If you're not sure it works it may be best to test a bit more before answering. \$\endgroup\$ – Calvin's Hobbies Jun 12 '16 at 4:26
  • \$\begingroup\$ Because security stuff (evaluation only works for + and - online) \$\endgroup\$ – Leaky Nun Jun 12 '16 at 4:26
  • \$\begingroup\$ @HelkaHomba I didn't have a chance to try it offline yet, but it should work. The online interpreter uses the --safe switch, which replaces eval with ast.literal_eval. \$\endgroup\$ – Dennis Jun 12 '16 at 4:31
  • \$\begingroup\$ Ok, fair enough. \$\endgroup\$ – Calvin's Hobbies Jun 12 '16 at 4:42
  • \$\begingroup\$ Confirmed, this works with the offline interpreter. \$\endgroup\$ – Dennis Jun 12 '16 at 5:16
12
\$\begingroup\$

Jelly, 18 16 15 14 bytes

I0;ð1g×⁹⁸œṗP€S

Uses no built-in eval. Try it online! or verify all test cases.

How it works

I0;ð1g×⁹⁸œṗP€S  Main link. Input: A (list)

I               Increments; compute the deltas of all adjacent items of A.
 0;             Prepend a 0.
   ð            Begin a new, dyadic chain.
                Left argument: D (0 plus deltas). Right argument: A
    1g          Compute the GCD of 1 and each item in D.
                This yields 1 for non-negative items, -1 for negative ones.
      ×⁹        Multiply each 1 or -1 with the corresponding item of A.
                This negates every item in A that follows a - sign.
        ⁸œṗ     Partition the result by D. This splits at occurrences of non-zero
                values of D, grouping items with identical absolute value.
           P€   Take the product of each group.
             S  Sum; add the results.
\$\endgroup\$
  • \$\begingroup\$ I out-golfed you! \$\endgroup\$ – Leaky Nun Jun 12 '16 at 6:04
  • 1
    \$\begingroup\$ Nicely done. I should add Python's eval as an atom... \$\endgroup\$ – Dennis Jun 12 '16 at 6:07
  • 9
    \$\begingroup\$ I out-out-golfed you. :P \$\endgroup\$ – Dennis Jun 12 '16 at 6:25
  • \$\begingroup\$ Nicely done, your turn! \$\endgroup\$ – Leaky Nun Jun 12 '16 at 6:29
9
\$\begingroup\$

MATL, 12 bytes

Y'^l6MdZSh*s

This uses @aditsu's very nice idea of run-length encoding.

Try it online!

Explanation

       % Take input vector implicitly
Y'     % RLE. Produces two vectors: values and lengths
^      % Rise each value to the number of consecutive times it appears. This
       % realizes the product of consecutive equal values
l      % Push 1
6M     % Push vector of values again
d      % Consecutive differences
ZS     % Sign function. Gives 1 or -1 (no 0 in this case)
h      % Concatenate horizontally with previous 1
*      % Multiply. This gives plus or minus depending on increasing character
s      % Sum of vector. This realizes the additions or subtractions
       % Display implicitly
\$\endgroup\$
  • \$\begingroup\$ Haha had just written up something similar. RLE works out well for this \$\endgroup\$ – Suever Jun 12 '16 at 13:42
  • \$\begingroup\$ @Suever I see :-D \$\endgroup\$ – Luis Mendo Jun 12 '16 at 14:59
7
\$\begingroup\$

CJam, 20

q~e`{~_W-g\:W@#*}%:+

Try it online

Explanation:

q~       read and evaluate the input (array of numbers)
e`       RLE encode, obtaining [count number] pairs
{…}%     map each pair
  ~_     dump the count and number on the stack, and duplicate the number
  W-     subtract the previous number (W is initially -1 by default)
  g      get the sign of the result
  \      swap with the other copy of the number
  :W     store it in W (for next iteration)
  @#     bring the count to the top, and raise the number to that power
  *      multiply with the sign
:+       add all the results together
\$\endgroup\$
7
\$\begingroup\$

JavaScript (ES6), 54

p=>eval(0+p.map(v=>x+='*-+'[(p>v)+2*(p<v)]+(p=v),x=1))

eval receives a comma separated list of expressions and returns the value of the last one.

Test

f=p=>eval(0+p.map(v=>x+='*-+'[(p>v)+2*(p<v)]+(p=v),x=1))

t=p=>(0+p.map(v=>x+='*-+'[(p>v)+2*(p<v)]+(p=v),x=1))

function Test() {
  var a=I.value.match(/\d+/g).map(x=>+x) // convert input to a numeric array
  
  var x=f(a),y=t(a)
  O.textContent='Value '+x+'\n(no eval '+y+')'
}  

Test()
#I { width:80%}
<input value='12, 0, 7, 7, 29, 10, 2, 2, 1' id=I>
<button onclick='Test()'>Test</button>
<pre id=O></pre>

\$\endgroup\$
  • 4
    \$\begingroup\$ That's the worst abuse of the comma operator that I can remember seeing on this site... \$\endgroup\$ – Neil Jun 12 '16 at 10:26
5
\$\begingroup\$

Julia, 76 57 bytes

!x=[[" ""-*+"[2+sign(diff(x))]...] x]'|>join|>parse|>eval

My first time golfing Julia, so maybe there are obvious improvements. Try it online!

Dennis saved a ton of bytes.

\$\endgroup\$
4
\$\begingroup\$

Pyth - 23 22 20 bytes

As with Kenny's, multiplication doesn't work online.

vs.i+\+@L"*+-"._M-Vt

Test Suite without doing eval.

\$\endgroup\$
  • \$\begingroup\$ Whoo is Kevin ? \$\endgroup\$ – Leaky Nun Jun 12 '16 at 4:43
  • \$\begingroup\$ @LeakyNun I forgot your name after a while >_> \$\endgroup\$ – Maltysen Jun 12 '16 at 4:43
  • \$\begingroup\$ @Maltysen Haha, you're thinking of kevin-not-kenny Lau \$\endgroup\$ – DJMcMayhem Jun 12 '16 at 4:57
  • \$\begingroup\$ Sorry, I was eating, so I could not golf my solution. Your turn. \$\endgroup\$ – Leaky Nun Jun 12 '16 at 5:14
  • \$\begingroup\$ @LeakyNun almost there \$\endgroup\$ – Maltysen Jun 12 '16 at 6:00
3
\$\begingroup\$

R, 92 bytes

There's likely still some good golfing that can be done here.

eval(parse(t=paste(i<-scan(),c(ifelse(d<-diff(i),ifelse(d>0,"+","-"),"*"),""),collapse="")))

Ungolfed:

i = scan()                # Read list from stdin
d = diff(i)               # Calculate difference between each element of list
s = ifelse(d,             # If d!=0
             ifelse(d>0,  # And if d>1
                    "+",  # Return plus
                    "-"), # Else return minus
             "*")         # Else (i.e. d==0) return multiply.
s = c(s,"")               # Pad the list s with an empty string, so it's the same
                          # length as i
p = paste(i,s,collapse="")# Paste the elements of i and s into one long string.
eval(parse(t=p))          # Evaluate the string as a language object.
\$\endgroup\$
3
\$\begingroup\$

Brachylog, 34 32 bytes

~b≜ḅ⟨h⟨h≡^⟩l⟩ᵐs₂ᶠ{zh>₁&ttṅ|tt}ᵐ+

Try it online!

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

TI-BASIC, 146 bytes

I'll format it nicely when not on mobile. Sleep escapes me, so you get this. Enjoy.

Prompt L₁
"(→Str1
For(A,1,dim(L₁
{0,1→L₂
{0,L₁(A→L₃
LinReg(ax+b) L₁,L₃,Y₁
Equ►String(Y₁,Str2
sub(Str2,1,-1+inString(Str2,"X→Str2
If A>1
Then
L₁(A-1
2+(Ans>L₁(A))-(Ans<L₁(A
Str1+sub("+*-",Ans,1→Str1
End
Str1+Str2→Str2
End
expr(Str1
\$\endgroup\$
2
\$\begingroup\$

Javascript ES6, 64 62 chars

a=>eval(a.map((x,i)=>x+('*+-'[x<a[++i]|(x>a[i])*2])).join``+1)
\$\endgroup\$
  • 3
    \$\begingroup\$ Should not this be a function and a a parameter? \$\endgroup\$ – edc65 Jun 12 '16 at 13:26
  • \$\begingroup\$ This is invalid as-is. \$\endgroup\$ – Rɪᴋᴇʀ Jun 12 '16 at 15:19
  • \$\begingroup\$ @edc65, yes, it should. But in fact it was counted (61 specified, but real code length was 59), I just badly copied a new code (the edit should be a[i+1]...a[i+1] => a[++i]...a[i] - 2 chars shorter, but I mistakenly replaced the whole code dropping a=>). \$\endgroup\$ – Qwertiy Jun 12 '16 at 19:39
  • \$\begingroup\$ @EᴀsᴛᴇʀʟʏIʀᴋ, it's just a wrong paste. See comment above and edit history for more detailes. \$\endgroup\$ – Qwertiy Jun 12 '16 at 19:40
  • \$\begingroup\$ @Qwertiy okay cool. Nice answer btw.. \$\endgroup\$ – Rɪᴋᴇʀ Jun 12 '16 at 19:42
1
\$\begingroup\$

Java, 384 bytes

int s(int[]l){int n=l[0],m;for(int i=0;i<l.length-1;i++)if(l[i]<l[i+1])if(i<l.length-2&&l[i+1]!=l[i+2])n+=l[i+1];else{m=l[i+1];while(i<l.length-2&&l[i+1]==l[i+2])m*=l[(i++)+1];n+=m;}else if(l[i]>l[i+1])if(i<l.length-2&&l[i+1]!=l[i+2])n-=l[i+1];else{m=l[i+1];while(i<l.length-2&&l[i+1]==l[i+2])m*=l[(i++)+1];n-=m;}else{m=l[i];while(i<l.length-1&&l[i]==l[i+1])m*=l[i++];n+=m;}return n;}

Ungolfed try online

int s(int[] l)
{
    int n=l[0], m;

    for(int i=0; i<l.length-1; i++)
    {
        if(l[i] < l[i+1])
        {
            if (i<l.length-2 && l[i+1]!=l[i+2])
            {
                n += l[i+1];
            }
            else
            {
                m = l[i+1];
                while(i<l.length-2 && l[i+1]==l[i+2]) m *= l[(i++)+1];
                n += m;
            }
        }
        else if(l[i] > l[i+1])
        {
            if (i<l.length-2 && l[i+1]!=l[i+2])
            {
                n -= l[i+1];
            }
            else
            {
                m = l[i+1];
                while(i<l.length-2 && l[i+1]==l[i+2]) m *= l[(i++)+1];
                n -= m;
            }
        }
        else
        {
            m = l[i];
            while(i<l.length-1 && l[i]==l[i+1]) m *= l[i++];
            n += m;
        }
    }

    return n;
}
\$\endgroup\$
  • 1
    \$\begingroup\$ Some quick golfs: int a=l.length, && => &, put the int i=0 on the same "line" as int n=l[0],m. \$\endgroup\$ – Leaky Nun Jun 12 '16 at 10:10
  • \$\begingroup\$ In if(i<l.length-2&&l[i+1]!=l[i+2])n+=l[i+1];else{m=l[i+1];while(i<l.length-2&&l[i+1]==l[i+2])m*=l[(i++)+1];n+=m;, you can just replace this with the content inside the else block. \$\endgroup\$ – Leaky Nun Jun 12 '16 at 10:11
1
\$\begingroup\$

Javascript ES6, 79 chars

a=>eval(`${a}`.replace(/(\d+),(?=(\d+))/g,(m,a,b)=>a+('*+-'[+a<+b|(+a>+b)*2])))
\$\endgroup\$
1
\$\begingroup\$

Perl, 49 bytes

48 bytes code + 1 for -p

s/\d+ (?=(\d+))/$&.qw(* - +)[$&<=>$1]/ge;$_=eval

Usage

perl -pe 's/\d+ (?=(\d+))/$&.qw(* - +)[$&<=>$1]/ge;$_=eval' <<< '12 0 7 7 29 10 2 2 1'
75

Notes

I learnt here that you can capture a lookahead in PCRE, although it's a little unintuitive ((?=(\d+)) instead of ((?=\d+))). It does make sense after reading though as you would be capturing a zero-length match (the lookahead) with the latter, and instead capture the match with the former).

Thanks to @ninjalj for saving 8 bytes!

\$\endgroup\$
  • \$\begingroup\$ @LeakyNun I never know exactly what to count for that, I can't find the relevant meta post, I'm happy to bump the count, but I thought that since you can run with -e for free, adding a p making it -pe was +1? Will update for now, but if you could find a source I could quote/link to going forward, that'd be awesome! \$\endgroup\$ – Dom Hastings Jun 12 '16 at 12:37
  • 3
    \$\begingroup\$ @DomHastings 1 is correct, per the reason you say + this meta post \$\endgroup\$ – Sp3000 Jun 12 '16 at 12:39
  • \$\begingroup\$ Thanks @Sp3000! I couldn't find that post for the life of me! @LeakyNun meta post for +1 as per comment from Sp3000 \$\endgroup\$ – Dom Hastings Jun 12 '16 at 12:47
  • \$\begingroup\$ Instead of using chained conditional operators, you can use the spaceship operator to select from a list: $&.qw(* - +)[$&<=>$1] in the replacement part of the s/// operator. \$\endgroup\$ – ninjalj Jun 13 '16 at 17:44
  • \$\begingroup\$ @ninjalj Of course! amazing, thanks! -8 with that! \$\endgroup\$ – Dom Hastings Jun 13 '16 at 18:12
1
\$\begingroup\$

Actually, 30 bytes

;2@VpXdX`i-su"+*-"E`M' @o♀+εj≡

Unfortunately, because the eval () command only evaluates literals on TIO, this program does not work on TIO.

Explanation:

;2@VpXdX`i-su"+*-"E`M' @o♀+εj≡
;                               duplicate input
 2@V                            overlapping sublists of length <= 2
    pXdX                        discard first and last element (length-1 sublists)
        `i-su"+*-"E`M           map: for each pair of elements
         i-su                     flatten, subtract, sign, increment (results in a 0 if b < a, 1 if b == a, and 2 if b > a)
             "+*-"E               select the correct operation
                     ' @o       put a space at the beginning of the list to pad it properly
                         ♀+     pairwise addition (since addition is not defined for strings and integers, this just zips the lists and flattens the result into a single flat list)
                           εj   join with empty string
                             ≡  eval
\$\endgroup\$
1
\$\begingroup\$

R, 120 44 bytes

r=rle(scan());c(1,sign(diff(r$v)))%*%r$v^r$l

Try it online!

The algorithm is similar to this answer's, but I only realized it after coding my answer. Much better than my original answer that was using eval(parse).

Fully leverages R's vectorized operations - does the * operation first using rle(x)$values ^ rle(x)$lenghts and dot-products this vector with sign( diff( rle(x)$values ) ) (predended with 1).

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

05AB1E (legacy), 17 16 15 bytes

ü.S…*-+sè‚ζJJ.E

-2 bytes thanks to @Emigna.

Try it online or verify all test cases.

Explanation:

ü                  # Pair-wise loop over the (implicit) input-list
                   #  i.e. [12,0,7,7] → [[12,0],[0,7],[7,7]]
 .S                # Calculate the signum of the pair (-1 for a<b; 0 for a==b; 1 for a>b)
                   #  i.e. [[12,0],[0,7],[7,7]] → [1,-1,0]
   …*-+sè          # Index over "*-+" (with wrap-around)
                   #  i.e. [1,-1,0] → ['-','+','*']
         ‚ζ        # Zip the two lists together (appending the operands to the numbers)
                   #  i.e. [12,0,7,7] and ['-','+','*','+']
                   #   → [[12,'-'],[0,'+'],[7,'*'],[7,' ']]
           JJ      # Join them together
                   #  [[12,'-'],[0,'+'],[7,'*'],[7,' ']] → '12-0+7*7 '
             .E    # Evaluate as Python code
                   #  i.e. '12-0+7*7' → 61
\$\endgroup\$
  • 1
    \$\begingroup\$ Due to modular indexing, you can remove > by moving + to the end of the string. \$\endgroup\$ – Emigna Aug 23 '18 at 7:10
  • \$\begingroup\$ @Emigna Not sure how I missed that.. Thanks! \$\endgroup\$ – Kevin Cruijssen Aug 23 '18 at 7:13
  • 1
    \$\begingroup\$ You can save another byte by removing Ć and ¨, if you use ‚ζ instead of ø \$\endgroup\$ – Emigna Aug 23 '18 at 7:18
  • \$\begingroup\$ @Emigna Oh, now that is smart! Thanks. I knew the enclose was a bit of a weird work-around, but didn't knew how to fix it. ‚ζ is a perfect alternative work-around, since the space is ignore in the eval. Thanks again. :) \$\endgroup\$ – Kevin Cruijssen Aug 23 '18 at 7:37
0
\$\begingroup\$

PHP, 103 bytes

Neat challenge. This got longer than expected. I think using array_map or similar won't improve the byte count, as anonymous functions are still expensive in PHP.

foreach(fgetcsv(STDIN)as$v)(0<=$p?$o.=$p.('*-+'[($p>$v)+2*($p<$v)]):_)&&$p=$v;echo eval("return$o$v;");

Runs from command line, will prompt for a comma separated list, like:

php array_to_math.php
12, 0, 7, 7, 29, 10, 2, 2, 1
\$\endgroup\$
0
\$\begingroup\$

PowerShell v2+, 62 bytes

-join($args|%{"$o"+'*+-'[($o-lt$_)+2*($o-gt$_)];$o=$_})+$o|iex

Takes input as space-separated command-line arguments, which gets converted into automatic array $args. We iterate through each element, using helper variable $o each iteration to remember what our previous entry was. We use a indexed-string to pull out the appropriate operator, done by performing math on the implicitly-converted Boolean values (e.g., if the previous entry is smaller, the [] evaluates to 1+2*0 so '*+-'[1] means the + is selected).

The concatenated strings are left on the pipeline. We collect all of those snippets together (e.g., 3-, 1+, 4-, etc.) with a -join operation, concatenate on the final number (implicitly converted to string), and pipe it to iex (alias for Invoke-Expression and similar to eval).

\$\endgroup\$
  • \$\begingroup\$ A concern is that if the caller has already given $o a value (say $o = 999) then the expression in this entry will not compute the correct value. An initialization of $o needs to be added to this solution. \$\endgroup\$ – Bevo Aug 12 '16 at 21:39
  • \$\begingroup\$ @Bevo This is intended to be a full script, executed via the command line, and not a function or via the interactive shell. The vast majority of my submissions are as such, since in such a scenario, there is no predefined variables to worry about and thus the code can be a bit shorter. \$\endgroup\$ – AdmBorkBork Aug 14 '16 at 3:52
0
\$\begingroup\$

Japt, 25 bytes

Would like to cut it shorter, but I couldn't make an eval-less version work.

S+Uä!- ®"*+-"gZÎì)íU
OxU

Try it online!

\$\endgroup\$
  • \$\begingroup\$ Got it down to 22 bytes but still think it can be improved on. \$\endgroup\$ – Shaggy Aug 24 '18 at 14:32
0
\$\begingroup\$

Japt -x, 21 19 bytes

änJ f mÎí*Uò¦ ®ÎpZÊ

Try it


Explanation

                        :Implicit input of array U
  J                     :Prepend -1
än                      :Get deltas
    f                   :Filter (remove 0s)
      m                 :Map
       Î                : Signs
        í               :Interleave
          U             :  Original input
           ò            :  Partition on
            ¦           :   Inequality
              ®         :  Map each sub-array Z
               Î        :    Get first element
                p       :    Raise to the power of
                 ZÊ     :     Length of Z
         *              :Reduce each pair of elements by multiplcation
                        :Implicitly reduce by addition and output
\$\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.