Kalkulator jako lista liczb i operatorów

20

Twoim zadaniem jest pobranie listy argumentów, które są liczbami całkowitymi lub operatorami, i parsowanie ich w następujący sposób:

  1. Obecny operator zaczyna się od +.

  2. Za każdym razem, gdy zostanie znaleziony operator, aktualny operator zmieni się na niego.

  3. Możliwe operatory to: „+”, „-”, „*”, „/” i „%”, które odpowiadają ich znaczeniom w języku C i większości języków.

  4. Zachowywane jest działające rozwiązanie, które zaczyna się od 0.

  5. Za każdym razem, gdy zostanie znaleziona liczba całkowita, rozwiązanie jest modyfikowane przez liczbę zależną od operatora; np. jeśli operatorem jest „/”, wówczas rozwiązanie jest dzielone przez liczbę.

  6. Jeśli operacja spowodowałaby powstanie liczby mieszanej (tj. Dziesiętnej), należy ją przenieść z powrotem do liczby całkowitej (tzn. Przecinek dziesiętny należy odciąć).

  7. Wyjście ostatecznego rozwiązania.

Na przykład:

Argumenty 5 8 25 * 9 6 2 - 104 / 4 7 + 6 % 14skutkowałyby:

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

Dane wejściowe będą w postaci argumentów wiersza polecenia lub funkcji lub równoważnych dla twojego języka.

Najkrótszy kod wygrywa!

Trebuchette
źródło
kiedy %wymawiasz znaczenia w C, masz na myśli dokładnie to samo, co w C, czy też jest w porządku, jeśli zaokrągla się w kierunku -inf zamiast 0?
Maltysen
@Maltysen: Cokolwiek robi Twój język.
Trebuchette,
3
Czy liczby całkowite z wejścia mogą być ujemne?
Dennis
Punkty 3 i 6 są ze sobą sprzeczne: w języku C i większości języków podział liczb całkowitych zaokrągla się w kierunku zera, a nie podłogi.
Peter Taylor
Ciekawie

Odpowiedzi:

6

Pyth - 24 23 22 20 bajtów

2 bajty zapisane dzięki @issacg i 1 dzięki @orlp!

Używa zmniejszania z podstawowym przypadkiem 0i sprawdza, czy 'jest w repr, aby wykryć ciąg vs. int.

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

Nie działa online, ponieważ używam pełnej wersji, która jest wyłączona online ze względów bezpieczeństwa. Zajmuje wejście od stdin na liście jako takie: 5, 8, 25, "*", 9, 6, 2, "-", 104, "/", 4, 7, "+", 6.

Maltysen
źródło
Możesz zapisać 2 bajty, przełączając się z ?na .x, ponieważ tylko blok else może zgłosić wyjątek, i zrobi to za każdym razem. Nie możesz Kjuż więcej korzystać . u.xsv++GbH&=bHG+\+QZ, konkretnie.
isaacg
6

JavaScript (ES6) 53

Funkcja przyjmująca tablicę jako dane wejściowe.

Uruchom fragment w przeglądarce Firefox, aby go przetestować.

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
źródło
4

Julia, 85 83 bajtów

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

Tworzy to nienazwaną funkcję, która akceptuje ciąg wejściowy i zwraca liczbę całkowitą.

Nie golfowany:

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

Naprawiono problem i zapisano 2 bajty dzięki Glen O.

Alex A.
źródło
Julia narzeka, że o is not definedkiedy próbujesz uruchomić tę funkcję na świeżo. Próbuje uruchomić funkcję „o = ifloor ...” w Main, a nie wewnątrz funkcji (patrz tutaj github.com/JuliaLang/julia/issues/2386 ). Czy mogę zasugerować s->(o=0;p="+";for i=split(s) isdigit(i)?o=eval(parse("ifloor($o$p$i)")):p=i;end;o)?
Glen O
@GlenO Nie wiem, jak tego nie złapałem. : / Dzięki, naprawiono.
Alex A.
4

elisp, 101 bajtów

Po przekazaniu argumentów jako cytowanej listy: np (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))

Wersja z nowymi liniami:

    (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
źródło
4

CJam, 24 bajty

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

Jest to pełny program, który odczytuje dane wejściowe jako argumenty wiersza poleceń.

Aby wypróbować kod online na tłumacza CJam (która nie obsługuje argumenty wiersza poleceń), wymienić eaz lS/odczytu z symulowanym stdin.

Jak to działa

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
źródło
3

JavaScript, 85 bajtów

r=0;o="+";prompt().split(" ").forEach(t=>+t+1?r=parseInt(eval(r+o+ +t)):o=t);alert(r)
Ypnypn
źródło
dlaczego o+ +t? i tak budujesz ciąg, nie musisz konwertować na liczbę. Co więcej, .forEachnie ma miejsca w Code Golf: use.map
edc65
... i ~~ zamiast 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 bajtów.
Ismael Miguel
3

Lua, 142 bajty

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

Nie golfowany:

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
źródło
3

PowerShell, 57 bajtów

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

bez golfa;

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

Jeśli zmienna niejawna w for-each jest operatorem, a nie liczbą, Wywołanie wyrażenia (POSH eval()) zakończy się niepowodzeniem, a status wykonania $?będzie fałszywy.

Podłoga w POSH jest nieporęczna - $foo=[math]::floor($foo)i $foo-=$foo%1była najbardziej golfową alternatywą, jaką mogłem wymyślić.

tomkandy
źródło
Ładny. Przeczytałem to trochę bardziej dosłownie, zakładając ciąg znaków i parsując go na spacjach, a następnie wpisując ifcyfry, ale zasadniczo tak samo. 89 bajtów $o="+";$r=0;$args-split'\s+'|%{if($_-match'^\d+$'){$r=iex $r$o$_;$r-=$r%1}Else{$o=$_}};$r
AdmBorkBork
3

GNU Sed (z rozszerzeniem eval, + dc), 102

(Wynik obejmuje +1 za opcję -r sed.)

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

Przekształca wyrażenie wejściowe w odwrotną notację polską, a następnie używa go dcdo oceny.

Wyjście testowe:

$ sed -rf calclist.sed <<< '5 8 25 * 9 6 2 - 104 / 4 7 + 6 % 14'
8
$ 
Cyfrowa trauma
źródło
2

CJam, 34 bajty

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

Wypróbuj online

Myślałem, że to będzie całkiem rozsądne. Ale nie byłem wystarczająco szybki, aby opublikować to, co najmniej na chwilę, jako najkrótszą odpowiedź CJam. :(

Reto Koradi
źródło
2

Python 3 - 131 bajtów 129 bajtów 121 bajtów 116 bajtów

Dzięki Maltysen za wygolenie dwóch bajtów, Beta Decay za wygolenie 8 i Steven Rumbalski za zgolenie 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

Próbuję wymyślić sposób na skrócenie długości instrukcji if, ale na razie wydaje się, że jestem tak golfistą, jak tylko mogę. Pobiera dane wejściowe jako listę.

kapusta
źródło
można zaoszczędzić kilka bajtów na wgniecenia i zastępowanie intz//1
Maltysen
także, dlaczego parens w `if?
Maltysen
@ Maltysen ups, zapomniałem, że nie potrzebowałem nawiasów w instrukcji if. Dzięki. Nie sądzę, aby użycie // 1 było dozwolone, chociaż nie pomyślałem, aby go użyć, ponieważ wydaje się, że pozostawia końcowe 0 (np. 10,0), co nie wydaje mi się dozwolone.
cole
nie sądzę, żebyś potrzebował tej przestrzeni między ini cytatu.
Maltysen
Możesz zapisać niektóre bajty, zakładając, że lista jest przekazywana w argumentach funkcji i pozbywana się .split().
Beta Decay
2

Bash, 69

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

Działa to tylko z nieujemnymi liczbami całkowitymi - nie jest jasne w pytaniu, czy jest to w porządku, czy nie.

Cyfrowa trauma
źródło
2

Groovy, 79 bajtów

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}

Próbny:

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

Nie golfowany:

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
źródło
1

gcc (z ostrzeżeniami) 165 (jeśli koniec linii liczy się jako 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);}

Ale jeśli kompilujesz go za pomocą mingw32, musisz wyłączyć globbing (patrz https://www.cygwin.com/ml/cygwin/1999-11/msg00052.html ), kompilując w ten sposób:

gcc x.c C:\Applications\mingw32\i686-w64-mingw32\lib\CRT_noglob.o
Jerry Jeremiasz
źródło
1

Perl 5.10+, 52 bajty

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

Próbny:

$ 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

(Pamiętaj, że *należy uciec z mojej powłoki, aby nie była interpretowana jako wzorzec globalny).

Nie golfowany:

$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
źródło
1

C #, 132 165 168 bajtów

Ta funkcja zakłada, że ​​dane wejściowe są prawidłowe. Jest to trudne dla C #, ponieważ nie ma evalodpowiednika.

Dzięki edc65 za oszczędność 33 bajtów!

Wcięty dla przejrzystości.

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
źródło
Możesz usunąć większość nowych linii.
Trebuchette,
Nie policzyłem żadnych nowych linii ani nieznacznych białych znaków.
Hand-E-Food,
1
132 using ?:->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 bajtów

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

Testowe uruchomienie:

$ ruby calc.rb <<< "5 8 25 * 9 6 2 - 104 / 4 7 + 6 % 14"
8
daniero
źródło