Une calculatrice comme une liste de nombres et d'opérateurs

20

Votre tâche consiste à prendre une liste d'arguments qui sont soit des entiers soit des opérateurs, et à les analyser comme ceci:

  1. Il existe un opérateur actuel, qui commence par +.

  2. Chaque fois qu'un opérateur est trouvé, l'opérateur actuel y changera.

  3. Les opérateurs possibles sont: "+", "-", "*", "/" et "%", qui correspondent à leur signification en C et dans la plupart des langues.

  4. Il existe une solution en cours d'exécution, qui commence à 0.

  5. Chaque fois qu'un entier est trouvé, la solution est modifiée par le nombre selon l'opérateur; Par exemple, si l'opérateur est "/", la solution est divisée par le nombre.

  6. Si une opération aboutit à un nombre mixte (c'est-à-dire avec une décimale), elle doit être renvoyée à un entier (c'est-à-dire que la décimale doit être coupée).

  7. Sortez la solution finale.

Par exemple:

Les arguments 5 8 25 * 9 6 2 - 104 / 4 7 + 6 % 14entraîneraient:

  5 8  25 * 9   6    2    - 104  / 4    7      + 6 % 14
0 5 13 38   342 2052 4104   4000   1000 142   148    8  -> 8

Les entrées seront des arguments de ligne de commande ou de fonction, ou un équivalent pour votre langue.

Le code le plus court gagne!

Trébuchette
la source
quand vous dites des significations en C, voulez-vous dire exactement comme elles le font en C, ou est-ce correct si des %arrondis vers -inf au lieu de 0?
Maltysen
@Maltysen: Quelle que soit votre langue.
Trebuchette
3
Les entiers d'entrée peuvent-ils être négatifs?
Dennis
Les points 3 et 6 se contredisent: en C et dans la plupart des langues, la division entière arrondit vers zéro plutôt que vers le sol.
Peter Taylor
Il serait intéressant de voir un autre défi similaire à celui-ci, mais incluant la priorité entre parenthèses ...
Joshpbarron

Réponses:

6

Pyth - 24 23 22 20 octets

2 octets enregistrés grâce à @issacg et 1 grâce à @orlp!

Utilise réduire avec le cas de base de 0et vérifie 'être en repr pour détecter la chaîne vs int.

u.xsv++GbH&=bHG+\+QZ

Ne fonctionne pas en ligne car j'utilise une évaluation complète qui est désactivée en ligne pour des raisons de sécurité. Prend entrée de stdin dans une liste en tant que telle: 5, 8, 25, "*", 9, 6, 2, "-", 104, "/", 4, 7, "+", 6.

Maltysen
la source
Vous pouvez économiser 2 octets en passant de ?à .x, car seul le bloc else peut lever une exception, et il le fera à chaque fois. Vous ne pouvez plus utiliser K, cependant. u.xsv++GbH&=bHG+\+QZ, Plus précisément.
isaacg
6

JavaScript (ES6) 53

Une fonction prenant un tableau en entrée.

Exécutez l'extrait dans Firefox pour tester.

f=a=>a.map(t=>t<'0'?o=t:v=eval(v+o+t)|0,v=0,o='+')&&v

// TEST
out=x=>O.innerHTML=x;

input = [5,8,25,"*",9,6,2,"-",104,"/",4,7,"+",6,"%",14];
out(input.join(' ')+' -> '+f(input));

function go() {
  i=I.value.split(/ +/),out(I.value+' -> '+f(i))
}  
<pre id=O></pre>
Your test:<input id=I><button onclick='go()'>GO</button>

edc65
la source
4

Julia, 85 83 octets

s->(o=0;p="+";for i=split(s) isdigit(i)?o=eval(parse("ifloor($o$p$i)")):(p=i)end;o)

Cela crée une fonction sans nom qui accepte une chaîne en entrée et renvoie un entier.

Non golfé:

function f(s::String)
    # Assign the starting output value o and operator p
    o = 0
    p = "+"

    # Split the input string into an array on spaces
    for i = split(s)
        if isdigit(i)
            # Assign o using string interpolation
            o = eval(parse("ifloor($o $p $i)"))
        else
            # Assign p to the new operator
            p = i
        end
    end
end

Correction d'un problème et économisé 2 octets grâce à Glen O.

Alex A.
la source
Julia se plaint que o is not definedlorsque vous essayez d'exécuter la fonction à nouveau. Il essaie d'exécuter la fonction "o = ifloor ..." dans Main, plutôt qu'à l'intérieur de la fonction (voir ici github.com/JuliaLang/julia/issues/2386 ). Puis-je suggérer s->(o=0;p="+";for i=split(s) isdigit(i)?o=eval(parse("ifloor($o$p$i)")):p=i;end;o)?
Glen O
@GlenO Je ne sais pas comment je n'ai pas compris ça. : / Merci, corrigé.
Alex A.
4

elisp, 101 octets

Avec les arguments passés sous forme de liste entre guillemets: par exemple (c '(5 5 * 10))

    (defun c(a)(let((f 0)(o '+))(dolist(x a)(if(not(integerp x))(setf o x)(setq f (eval(list o f x)))))f))

Version avec de nouvelles lignes:

    (defun c (a)
      (let ((f 0)
            (o '+))
        (dolist (x a)
          (if (not (integerp x))
              (setf o x) 
            (setq f (eval (list o f x)))))
        f))
Soupy
la source
4

CJam, 24 octets

0'+ea+{_A,s&O{:O;}?S}%s~

Il s'agit d'un programme complet qui lit l'entrée en tant qu'arguments de ligne de commande.

Pour essayer le code en ligne dans l' interpréteur CJam (qui ne prend pas en charge les arguments de ligne de commande), remplacez eapar lS/pour lire à partir de STDIN simulé.

Comment ça fonctionne

0'+                       Push a 0 and the character '+'.
   ea                     Push the array of command-line arguments.
     +                    Prepend the character to the array.
      {             }%    For each element:
       _                    Push a copy.
        A,s                 Push "0123456789".
           &                Intersect the copy with the string of digits.
             {   }?         If the intersection is non-empty:
            O                 The element is a number. Push O.
              :O;             The element is an operator. Save it in O.
                   S        Push a space.
                      s~  Flatten the array of strings and evaluate it.
Dennis
la source
3

JavaScript, 85 octets

r=0;o="+";prompt().split(" ").forEach(t=>+t+1?r=parseInt(eval(r+o+ +t)):o=t);alert(r)
Ypnypn
la source
pourquoi o+ +t? vous créez une chaîne de toute façon, pas besoin de convertir en nombre. De plus, .forEachn'a pas sa place dans Code Golf: utilisation.map
edc65
... et ~~ au lieu de parseInt ( codegolf.stackexchange.com/a/2788/21348 )
edc65
prompt(o="+",r=0).split(" ").forEach(t=>+t+1?r=+eval(r+o+ +t):o=t);alert(r)-> 75 octets.
Ismael Miguel
3

Lua, 142 octets

function f(s)o="+"r=0 for c in s:gmatch"%S+" do if tonumber(c)~=nil then loadstring("r=r"..o..c)() else o=c end r=math.floor(r)end print(r)end

Non golfé:

function f(s)
    o="+" --original operator
    r=0 --return value
    for c in s:gmatch"%S+" do --split by spaces
        if tonumber(c)~=nil then --check if the current character is a number
            loadstring("r=r"..o..c)() --appends the current operator and current character ex "r=r+5" and then evaluates as another Lua script 
        else 
            o=c --if the character is not a number, it is the new operator
        end
        r=math.floor(r) --floor after each operation
    end 
    print(r) --print the result
end
Nikolai97
la source
3

Powershell, 57 octets

$o="+"
$args|%{$r=iex "$r$o$_"
if(!$?){$o=$_}$r-=$r%1}
$r

non golfé;

$operator="+"
$args | ForEach-Object
{
    $result = Invoke-Expression "$result $operator $_"
    if(!$?)
    {
        $operator=$_
    }
    $result -= $result % 1
}
$result

Si la variable implicite dans le for-each est un opérateur plutôt qu'un nombre, Invoke-Expression (POSH eval()) échouera et le statut d'exécution $?sera faux.

Le sol de POSH est difficile à manier - $foo=[math]::floor($foo)et $foo-=$foo%1c'était l'alternative la plus golfique à laquelle je pouvais penser.

tomkandy
la source
Agréable. Je l'ai lu un peu plus littéralement en supposant une entrée de chaîne et en l'analysant sur des espaces, puis ifsur des chiffres, mais essentiellement les mêmes. 89 octets $o="+";$r=0;$args-split'\s+'|%{if($_-match'^\d+$'){$r=iex $r$o$_;$r-=$r%1}Else{$o=$_}};$r
AdmBorkBork
3

GNU Sed (avec l'extension eval, + dc), 102

(Le score inclut +1 pour l'option -r à sed.)

s/.*/0 + &p/
s/([-+/*%]) ([0-9]+)/\2 \1/g
:
s/([-+/*%] )([0-9]+ )([0-9]+)/\1\2\1\3/
t
s/.*/dc<<<'&'/e

Transforme l'expression d'entrée pour inverser la notation polonaise, puis l'utilise dcpour l'évaluer.

Sortie de test:

$ sed -rf calclist.sed <<< '5 8 25 * 9 6 2 - 104 / 4 7 + 6 % 14'
8
$ 
Traumatisme numérique
la source
2

CJam, 34 octets

'+0lS/{"+-*/%"1$#){@;\}{i2$~}?}/\;

Essayez-le en ligne

Je pensais que cela allait être assez raisonnable. Mais je n'ai pas été assez rapide pour la poster pour être la réponse CJam la plus courte au moins pendant un moment. :(

Reto Koradi
la source
2

Python 3 - 131 octets 129 octets 121 octets 116 octets

Merci à Maltysen pour avoir rasé deux octets, Beta Decay pour avoir rasé 8 et Steven Rumbalski pour avoir rasé 5.

def f(x):
    a,b="+",0
    for i in x:
        if i in"+-*/%":a=i
        else:b=int(eval(str(b)+a+i))
    return b

J'essaie de trouver un moyen de réduire la longueur de la déclaration if, mais pour l'instant cela semble aussi golfique que possible. Prend la saisie sous forme de liste.

cole
la source
vous pouvez enregistrer quelques octets sur l'indentation et le remplacer intpar//1
Maltysen
aussi, pourquoi les parens dans le `si?
Maltysen
@ Maltysen whoops, j'ai oublié que je n'avais pas besoin des parenthèses dans l'instruction if. Merci. Je ne pense pas que l'utilisation de // 1 sera autorisée, même si je ne pensais pas l'utiliser, car il semble laisser un 0 de fin (par exemple 10.0) qui, je pense, n'est pas autorisé.
cole
je ne pense pas que vous ayez besoin de cet espace entre inet la citation.
Maltysen du
Vous pouvez enregistrer quelques octets en supposant que la liste est passée dans les arguments de fonction et en vous en débarrassant .split().
Beta Decay
2

Bash, 69

set -f
for t in $*
do
((1${t}1>2))&&((r${o-+}=$t))||o=$t
done
echo $r

Cela ne fonctionne qu'avec des entiers non négatifs - ce n'est pas clair dans la question si c'est correct ou non.

Traumatisme numérique
la source
2

Groovy, 79 octets

def f(x,a=0,b='+'){x.each{z->a=z=~/\d/?Eval.me(a+b+z)as int:a;b=z=~/\d/?b:z};a}

Démo:

groovy> f([5,8,25,'*',9,6,2,'-',104,'/',4,7,'+',6,'%', 14])
Result: 8

Non golfé:

def f(x, a=0, b='+') {                                   
    x.each {z->
        a = z =~ /\d/ ? Eval.me(a+b+z) as int : a
        b = z =~ /\d/ ? b : z
    }
    a
}
egyb2h9
la source
1

gcc (avec avertissements) 165 (si la fin de ligne compte comme 1)

#define A atoi(*a);break;case
o='+',s=0;main(c,a)char**a;{while(*++a)if(**a<48)o=**a;else switch(o){case'+':s+=A'-':s-=A'*':s*=A'/':s/=A'%':s%=A 0:;}printf("%d",s);}

Mais si vous le compilez avec mingw32, vous devez désactiver la globalisation (voir https://www.cygwin.com/ml/cygwin/1999-11/msg00052.html ) en compilant comme ceci:

gcc x.c C:\Applications\mingw32\i686-w64-mingw32\lib\CRT_noglob.o
Jerry Jeremiah
la source
1

Perl 5.10+, 52 octets

perl -E '$o="+";/\D/?$o=$_:eval"\$x=int\$x$o$_"for@ARGV;say$x'

Démo:

$ perl -E '$o="+";/\D/?$o=$_:eval"\x=int\$x$o$_"for@ARGV;say$x' 5 8 25 \* 9 6 2 - 104 / 4 7 + 6 % 14
8

(Notez que cela *doit être échappé dans mon shell afin qu'il ne soit pas interprété comme un motif global.)

Non golfé:

$o="+";                      # Start with addition
/\D/ ? $o=$_                 # If not a number, update the current operator
     : eval"\$x=int\$x$o$_"  # Otherwise, make a string like '$x=int$x+1' and eval it
for@ARGV;                    # Repeat for each item in the argument list
say$x                        # Print the result
ThisSuitIsBlackNot
la source
1

C #, 132 165 168 octets

Cette fonction suppose que l'entrée est valide. C'est difficile pour C # étant donné qu'il n'y a pas d' evaléquivalent.

Merci edc65 pour avoir économisé 33 octets!

En retrait pour plus de clarté.

int C(string[]a){
    int o=1,r=0,n;
    foreach(var b in a)
        n=int.TryParse(b,out n)
            ?r=o<0?r%n
              :o<1?r*n
              :o<2?r+n
              :o<4?r-n
                  :r/n
            :o=b[0]-42;
    return r;
}
Hand-E-Food
la source
Vous pouvez supprimer la plupart des nouvelles lignes.
Trebuchette
Je n'ai pas compté de nouvelles lignes ou d'espaces insignifiants.
Hand-E-Food du
1
132 utilisant ?:->int C(string[]a){int o=1,r=0,n;foreach(var b in a)n=int.TryParse(b,out n)?r=o<0?r%n:o<1?r*n:o<3?r+n:o<5?r-n:r/n:o=b[0]-42;return r;}
edc65
1

Rubis, 59 octets

a=0
o=?+
gets.split.map{|s|s=~/\d/?a=eval([a,s]*o):o=s}
p a

Essai:

$ ruby calc.rb <<< "5 8 25 * 9 6 2 - 104 / 4 7 + 6 % 14"
8
daniero
la source