Uma calculadora como uma lista de números e operadores

20

Sua tarefa é pegar uma lista de argumentos inteiros ou operadores e analisá-los da seguinte maneira:

  1. Existe um operador atual, que inicia como +.

  2. Cada vez que um operador é encontrado, o operador atual muda para ele.

  3. Os possíveis operadores são: "+", "-", "*", "/" e "%", que correspondem aos significados em C e na maioria dos idiomas.

  4. Há uma solução em execução mantida, que começa em 0.

  5. Cada vez que um número inteiro é encontrado, a solução é modificada pelo número, dependendo do operador; por exemplo, se o operador for "/", a solução será dividida pelo número.

  6. Se uma operação resultar em um número misto (isto é, com um decimal), ela deve ser convertida em um número inteiro (isto é, o decimal deve ser cortado).

  7. Saída da solução final.

Por exemplo:

Os argumentos 5 8 25 * 9 6 2 - 104 / 4 7 + 6 % 14resultariam em:

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

As entradas serão como argumentos de linha de comando ou função, ou um equivalente para o seu idioma.

O menor código vence!

Trebuchette
fonte
Quando você diz significados em C, você quer dizer exatamente como eles fazem em C, ou tudo bem se %arredondar para -inf em vez de 0?
Maltysen
@ Maltysen: O que quer que seu idioma faça.
Trebuchette
3
Os números inteiros da entrada podem ser negativos?
Dennis
Os pontos 3 e 6 se contradizem: em C e na maioria dos idiomas, a divisão inteira é arredondada para zero, em vez de para o piso.
Peter Taylor
Seria interessante ver outro desafio semelhante a este, mas incluindo precedência parêntese ...
Joshpbarron

Respostas:

6

Pyth - 24 23 22 20 bytes

2 bytes salvos graças ao @issacg e 1 graças ao @orlp!

O uso reduz com o caso base 0e verifica se 'está em repr para detectar string vs. int.

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

Não funciona on-line porque eu uso o eval completo, que está desativado on-line por motivos de segurança. Toma a entrada de stdin em uma lista como tal: 5, 8, 25, "*", 9, 6, 2, "-", 104, "/", 4, 7, "+", 6.

Maltysen
fonte
Você pode salvar 2 bytes alternando de ?para .x, porque apenas o bloco else pode lançar uma exceção, e isso sempre será feito. Você não pode mais usar K, no entanto. u.xsv++GbH&=bHG+\+QZespecificamente.
Isaacg 01/09
6

JavaScript (ES6) 53

Uma função que recebe uma matriz como entrada.

Execute o trecho no Firefox para testar.

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
fonte
4

Julia, 85 83 bytes

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

Isso cria uma função sem nome que aceita uma string como entrada e retorna um número inteiro.

Ungolfed:

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

Foi corrigido o problema e salvou 2 bytes graças a Glen O.

Alex A.
fonte
Julia reclama que o is not definedquando você tenta executar a função recentemente. Ele tenta executar a função "o = ifloor ..." no Main, em vez de dentro da função (veja aqui github.com/JuliaLang/julia/issues/2386 ). Posso sugerir s->(o=0;p="+";for i=split(s) isdigit(i)?o=eval(parse("ifloor($o$p$i)")):p=i;end;o)?
Glen O
@GlenO Eu não sei como não entendi isso. : / Obrigado, corrigido.
Alex A.
4

elisp, 101 bytes

Com os argumentos passados ​​como uma lista citada: por exemplo (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))

Versão com novas linhas:

    (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
fonte
4

CJam, 24 bytes

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

Este é um programa completo que lê a entrada como argumentos da linha de comando.

Para experimentar o código online no interpretador CJam (que não suporta argumentos de linha de comando), substitua eapor lS/para ler a partir de STDIN simulado.

Como funciona

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
fonte
3

JavaScript, 85 bytes

r=0;o="+";prompt().split(" ").forEach(t=>+t+1?r=parseInt(eval(r+o+ +t)):o=t);alert(r)
Ypnypn
fonte
por que o+ +t? você está criando uma string de qualquer maneira, não há necessidade de converter para número. Além disso, .forEachnão tem lugar no Code Golf: use.map
edc65 1/15
... e ~~ em vez de parseInt ( codegolf.stackexchange.com/a/2788/21348 )
edc65 1/15
prompt(o="+",r=0).split(" ").forEach(t=>+t+1?r=+eval(r+o+ +t):o=t);alert(r)-> 75 bytes.
Ismael Miguel
3

Lua, 142 bytes

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

Ungolfed:

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
fonte
3

PowerShell, 57 bytes

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

não-destruído;

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

Se a variável implícita no for-each for um operador, e não um número, a Invoke-Expression (POSH's eval()) falhará e o status de execução $?será falso.

Andar em POSH é pesado - $foo=[math]::floor($foo)e $foo-=$foo%1foi a alternativa mais golfista que eu conseguia pensar.

tomkandy
fonte
Agradável. Eu o li um pouco mais literalmente, assumindo uma entrada de string e analisando-a em espaços, depois ifdigitando dígitos, mas essencialmente o mesmo. 89 Bytes $o="+";$r=0;$args-split'\s+'|%{if($_-match'^\d+$'){$r=iex $r$o$_;$r-=$r%1}Else{$o=$_}};$r
AdmBorkBork
3

GNU Sed (com a extensão eval, + dc), 102

(A pontuação inclui +1 na opção -r para sed.)

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

Transforma a expressão de entrada em notação de polimento reverso e, em seguida, usa-a dcpara avaliá-la.

Saída de teste:

$ sed -rf calclist.sed <<< '5 8 25 * 9 6 2 - 104 / 4 7 + 6 % 14'
8
$ 
Trauma Digital
fonte
2

CJam, 34 bytes

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

Experimente online

Eu pensei que isso seria bastante razoável. Mas não fui rápido o suficiente para publicá-la para ser a resposta mais curta do CJam, pelo menos por um momento. :(

Reto Koradi
fonte
2

Python 3 - 131 bytes 129 bytes 121 bytes 116 bytes

Agradecimentos a Maltysen por cortar dois bytes, Beta Decay por cortar 8 e Steven Rumbalski por cortar 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

Estou tentando descobrir uma maneira de reduzir o tamanho da instrução if, mas por enquanto isso parece o máximo possível. Leva a entrada como uma lista.

Cole
fonte
você pode salvar alguns bytes no recuo e substituindo intpor//1
Maltysen
Além disso, por que o parens no `if?
Maltysen
@ Maltysen opa, eu esqueci que não precisava dos parênteses na declaração if. Obrigado. Eu não acho que o uso de // 1 seja permitido, embora eu não tenha pensado em usá-lo, pois parece deixar um 0 à direita (por exemplo, 10,0), que eu acho que não é permitido.
Cole
não acho que você precise desse espaço entre ine a citação.
Maltysen
Você pode salvar alguns bytes assumindo que a lista seja passada nos argumentos da função e se livrando .split().
Decay Beta
2

Bash, 69

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

Isso funciona apenas com números inteiros não negativos - não está claro na pergunta se está ok ou não.

Trauma Digital
fonte
2

Groovy, 79 bytes

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}

Demo:

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

Ungolfed:

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
fonte
1

gcc (com avisos) 165 (se o final da linha contar como 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);}

Mas se você estiver compilando com o mingw32, precisará desativar o globbing (consulte https://www.cygwin.com/ml/cygwin/1999-11/msg00052.html ) compilando assim:

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

Perl 5.10+, 52 bytes

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

Demo:

$ 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

(Observe que *deve ser escapado no meu shell para que não seja interpretado como um padrão glob.)

Ungolfed:

$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
fonte
1

C #, 132 165 168 bytes

Esta função assume que a entrada é válida. Isso é difícil para o C #, pois não há evalequivalente.

Obrigado edc65 por salvar 33 bytes!

Recuado para maior clareza.

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;
}
Mão-E-Comida
fonte
Você pode remover a maioria das novas linhas.
Trebuchette
Não contei nenhuma linha nova ou espaço em branco insignificante.
Hand-E-Food
1
132 usando ?:->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

Ruby, 59 bytes

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

Execução de teste:

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