Transformez un tableau en problème mathématique

35

Étant donné une liste non vide d’entiers non négatifs, envisagez de la récrire en tant que problème arithmétique, dans lequel:

  • Un signe plus ( +) est inséré entre des paires de nombres qui augmentent de gauche à droite (du début à la fin de la liste).
  • Un signe moins ( -) est inséré entre des paires de nombres qui diminuent de gauche à droite.
  • Un signe de multiplication ( *) est inséré entre des paires de nombres égaux.

Dit autrement: toute sous-liste a,bdevient a+bsi a<b, a-bsi a>bet a*bsi a==b.

Par exemple, la liste

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

deviendrait l'expression

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

qui évalue à 75 .

Ecrivez un programme ou une fonction qui prend une telle liste et l'évalue, imprimant ou renvoyant le résultat.

  • L'ordre des opérations est important. Les multiplications doivent être effectuées avant toute addition ou soustraction.
  • Si la liste d'entrée a un numéro, ce doit être ce à quoi elle est évaluée. par exemple [64]devrait donner 64.
  • L'utilisation de evalou de execconstructions similaires est autorisée.

Voici quelques exemples supplémentaires:

[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

Le code le plus court en octets gagne. Tiebreaker est une réponse plus tôt.

Les passe-temps de Calvin
la source
5
En ce qui concerne "l'ordre des opérations", il peut être utile d'indiquer explicitement que l'addition et la soustraction sont associatives à gauche et ont la même priorité.
Martin Ender

Réponses:

15

Python 2, 63 octets

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

Construit et evals la chaîne d'expression. Le symbole arithmétique est choisi en comparant le nombre précédent au nombre pactuel x. Le symbole est ajouté suivi du numéro actuel.

Le premier numéro est traité avec une astuce intelligente de Sp3000. La valeur initiale de pest définie sur une chaîne, qui est supérieure à tout nombre et entraîne donc un -avant le premier nombre. Mais, ss’initialise en print-même temps que le résultat commence par print--(merci à xsot d’avoir économisé 2 octets en initialisant avec print.)

Xnor
la source
Je pense que vous pouvez vous déplacer printdans la chaîne et utiliser à la execplace de eval.
Xsot
13

Pyth, 31 26 19 17 16 15 octets

Les expressions avec *n'évaluent pas en ligne, mais elles fonctionnent théoriquement.

2 octets grâce à Maltysen.

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

Suite de tests (avec évaluation).

Les autres cas (sans évaluation).

Histoire

  • 31 octets: M+G@"*-+"->GH<GHv+sgMC,JsMQtJ\x60e
  • 26 octets: M+G@"*-+"->GH<GHv+sgVQtQ\x60e
  • 19 octets: vtssVm@"*-+"->Zd<~Z
  • 17 octets: vtssVm@"*-+"._-~Z
  • 16 octets: vssVm@"*-+"._-~k
  • 15 octets: vsm+@"*-+"._-~k
Fuite Nun
la source
Why won't multiplication work online? If you're not sure it works it may be best to test a bit more before answering.
Calvin's Hobbies
Because security stuff (evaluation only works for + and - online)
Leaky Nun
@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.
Dennis
Ok, fair enough.
Calvin's Hobbies
Confirmed, this works with the offline interpreter.
Dennis
12

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.
Dennis
la source
I out-golfed you!
Leaky Nun
1
Nicely done. I should add Python's eval as an atom...
Dennis
9
I out-out-golfed you. :P
Dennis
Nicely done, your turn!
Leaky Nun
9

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
Luis Mendo
la source
Haha had just written up something similar. RLE works out well for this
Suever
@Suever I see :-D
Luis Mendo
7

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
aditsu
la source
7

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>

edc65
la source
4
That's the worst abuse of the comma operator that I can remember seeing on this site...
Neil
5

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.

Lynn
la source
Nice job. I didn't realize you can define a custom function for !.
Rɪᴋᴇʀ
@Eᴀsᴛᴇʀʟʏ Iʀᴋ codegolf.stackexchange.com/a/81028/12012
Dennis
4

Pyth - 23 22 20 bytes

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

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

Test Suite without doing eval.

Maltysen
la source
Whoo is Kevin ?
Leaky Nun
@LeakyNun I forgot your name after a while >_>
Maltysen
@Maltysen Haha, you're thinking of kevin-not-kenny Lau
DJMcMayhem
Sorry, I was eating, so I could not golf my solution. Your turn.
Leaky Nun
@LeakyNun almost there
Maltysen
3

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.
rturnbull
la source
I managed to save just one byte using an indexing approach
JayCe
3

Brachylog, 34 32 bytes

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

Try it online!

Kroppeb
la source
2

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
Conor O'Brien
la source
2

Javascript ES6, 64 62 chars

a=>eval(a.map((x,i)=>x+('*+-'[x<a[++i]|(x>a[i])*2])).join``+1)
Qwertiy
la source
3
Should not this be a function and a a parameter?
edc65
This is invalid as-is.
Rɪᴋᴇʀ
@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=>).
Qwertiy
@EᴀsᴛᴇʀʟʏIʀᴋ, it's just a wrong paste. See comment above and edit history for more detailes.
Qwertiy
@Qwertiy okay cool. Nice answer btw..
Rɪᴋᴇʀ
1

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;
}
Khaled.K
la source
1
Some quick golfs: int a=l.length, && => &, put the int i=0 on the same "line" as int n=l[0],m.
Leaky Nun
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.
Leaky Nun
1

Javascript ES6, 79 chars

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

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!

Dom Hastings
la source
@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!
Dom Hastings
3
@DomHastings 1 is correct, per the reason you say + this meta post
Sp3000
Thanks @Sp3000! I couldn't find that post for the life of me! @LeakyNun meta post for +1 as per comment from Sp3000
Dom Hastings
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.
ninjalj
@ninjalj Of course! amazing, thanks! -8 with that!
Dom Hastings
1

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
Mego
la source
1

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).

JayCe
la source
1

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
Kevin Cruijssen
la source
1
Due to modular indexing, you can remove > by moving + to the end of the string.
Emigna
@Emigna Not sure how I missed that.. Thanks!
Kevin Cruijssen
1
You can save another byte by removing Ć and ¨, if you use ‚ζ instead of ø
Emigna
@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. :)
Kevin Cruijssen
0

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
insertusernamehere
la source
0

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).

AdmBorkBork
la source
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.
Bevo
@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.
AdmBorkBork
0

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!

Nit
la source
Got it down to 22 bytes but still think it can be improved on.
Shaggy
0

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
Shaggy
la source