Ocena nawiasów i nawiasów jako liczb całkowitych

20

Napisz program, który pobiera ciąg czterech znaków, ()[]który spełnia następujące warunki:

  • Każdy lewy nawias (ma pasujący prawy nawias ).
  • Każdy lewy wspornik [ma pasujący prawy wspornik ].
  • Pasujące pary nawiasów i nawiasów nie będą się nakładać. np. [(])jest niepoprawny, ponieważ pasujące nawiasy nie są w pełni zawarte w pasujących nawiasach, i odwrotnie.
  • Pierwszy i ostatni znak to pasująca para nawiasów lub nawiasów. Tak ([]([]))i [[]([])]są ważne, ale []([])nie są.

( Gramatyka formatu wejściowego to <input> ::= [<input>*] | (<input>*).)

Każda para pasujących nawiasów i nawiasów przyjmuje wartość całkowitą nieujemną:

  • Wszystkie pary w pasujących nawiasach są sumowane . Puste dopasowanie ()ma wartość 0.
  • Wszystkie pary w pasujących nawiasach są mnożone . Puste dopasowanie []ma wartość 1.

( Suma lub iloczyn jednego numeru to ta sama liczba).

Na przykład ([](())([][])[()][([[][]][][])([][])])można podzielić i ocenić jako 9:

([](())([][])[()][([[][]][][])([][])])    <input>
(1 (0 )(1 1 )[0 ][([1 1 ]1 1 )(1 1 )])    <handle empty matches>
(1 0   2     0   [(1     1 1 )2     ])    <next level of matches>
(1 0   2     0   [3           2     ])    <and the next>
(1 0   2     0   6                   )    <and the next>
9                                         <final value to output>

Inny przykład:

[([][][][][])([][][])([][][])(((((([][]))))))]    <input>
[(1 1 1 1 1 )(1 1 1 )(1 1 1 )((((((1 1 ))))))]
[5           3       3       (((((2     )))))]
[5           3       3       ((((2       ))))]
[5           3       3       (((2         )))]
[5           3       3       ((2           ))]
[5           3       3       (2             )]
[5           3       3       2               ]
90                                                <output>

Twój program musi ocenić i wydrukować liczbę całkowitą reprezentowaną przez cały ciąg wejściowy. Możesz założyć, że dane wejściowe są prawidłowe. Najkrótszy kod w bajtach wygrywa.

Zamiast programu możesz napisać funkcję, która pobiera ciąg znaków i wypisuje lub zwraca liczbę całkowitą.

Hobby Calvina
źródło
Pytanie w imieniu użytkownika Python o wyjaśnienie: Tylko program, czy funkcje / zwracana wartość są w porządku?
Sp3000,
W takim razie dobrze byłoby edytować pytanie. W poprzednim pytaniu powiedziano mi, że funkcje są niepoprawne, jeśli w pytaniu jest napisane „napisz program”.
Reto Koradi,

Odpowiedzi:

11

CJam, 23

q"])(""1]:*0]:+["4/ers~

Z DUŻYMI ​​kredytami dla Dennisa! Wypróbuj online

Wyjaśnienie:

Program konwertuje dane wejściowe na wyrażenie CJam, a następnie je ocenia.
[…]staje się […1]:*(dołącz 1 i pomnóż)
(…)staje się […0]:+(dodaj 0 i dodaj)

q              read input
"])("          characters we want to replace
"1]:*0]:+["    replacement strings, concatenated
4/             split into strings of length 4: ["1]:*" "0]:+" "["]
er             replace (transliterate) the 3 characters with the 3 strings
s              convert the result (mixed characters and strings) to string
~              evaluate
aditsu
źródło
1
Transliteracja oszczędza 4 bajty:q"])(""1]:*0]:+["4/ers~
Dennis
2
@Dennis whaaa! To szalone, możesz to zrobić?
aditsu
3
Ci proszą mnie ? : P
Dennis
4
@Dennis Skąd twórca CJam wiedziałby o istnieniu takiej funkcji?
Optymalizator
8

Common Lisp - 98

(lambda(s)(eval(read-from-string(#1=ppcre:regex-replace-all"\\["(#1#"]"(#1#"\\("s"(+")")")"(*"))))
  1. Zastąp (przez(+
  2. Zastąp [przez(*
  3. Zastąp ]przez)
  4. Odczyt z ciągu
  5. Eval

Wymaga cl-ppcreto załadowania biblioteki do bieżącego obrazu lisp.

Wyjaśnienie

Funkcje *i +są różne i zwracają swoją neutralną wartość, gdy nie podano argumentów. W twoich przykładach oceniana forma seplenienia jest następująca:

(+ (*) (+ (+)) (+ (*) (*)) (* (+)) (* (+ (* (*) (*)) (*) (*)) (+ (*) (*))))
=> 9

i

(* (+ (*) (*) (*) (*) (*)) (+ (*) (*) (*)) (+ (*) (*) (*))
   (+ (+ (+ (+ (+ (+ (*) (*))))))))
=> 90

Bez wyrażeń regularnych - 183 bajtów

(lambda(s)(do(r(x(coerce s'list))c)((not x)(eval(read-from-string(coerce(reverse r)'string))))(setq c(pop x))(push(case c(#\[ (push #\* r)#\()(#\] #\))(#\( (push #\+ r) #\()(t c))r)))

Dalej, Lisp - 16 bajtów (eksperymentalnie)

+((<r*([<r)]<rRE

Inne języki są tak zwięzłe, że kusi mnie tworzenie własnego języka golfowego opartego na Common Lisp do krótszych manipulacji strunami. Obecnie nie ma specyfikacji, a funkcja eval jest następująca:

(defun cmon-lisp (expr &rest args)
  (apply
   (lambda (s)
     (let (p q)
       (loop for c across expr
             do (case c
                  (#\< (push (pop p) q))
                  (#\r
                   (let ((a1 (coerce q 'string)) (a2 (coerce p 'string)))
                     (setf p nil
                           q nil
                           s
                             (cl-ppcre:regex-replace-all
                              (cl-ppcre:quote-meta-chars a1) s a2))))
                  (#\R
                   (setf s
                           (if (string= s "")
                               nil
                               (read-from-string s))))
                  (#\E (setf s (eval s)))
                  (t (push c p))))
       s))
   args))

Testy:

(cmon-lisp "+((<r*([<r)]<rRE" "([] [] ([] []))")
=> 4
  • istnieje domyślny argument o nazwie si dwa stosy, poraz q.
  • znaki w kodzie źródłowym są wypychane do p.
  • <: wyskakuje z pi popycha do q.
  • r: zamienia in s(musi być ciągiem) ze znaków in qna charactes in p; wynik jest przechowywany w s; pi qsą opróżniane.
  • R: odczyt z ciągu s, zapisz wynik w zmiennej s.
  • E: forma ewaluacyjna s, zapisz wynik w s.
rdzeń rdzeniowy
źródło
1
Funyy, jak lisp jest tutaj używany do robienia nawiasów klamrowych.
Syd Kerckhove,
@SydKerckhove Twój komentarz tylko każe mi wymyślić odpowiednią odpowiedź Clojure. Wielkie dzięki!
coredump
6

Pyth, 35 34 33 bajtów

L?*F+1yMbqb+YbsyMbyvsXzJ"])"+R\,J

Demonstracja.

1 bajt dzięki @Jakube.

Zaczynamy od przeanalizowania danych wejściowych. Format wejściowy jest zbliżony do Pythona, ale niezupełnie. Potrzebujemy przecinków po każdej nawiasowej lub nawiasowej grupie. Przecinek na końcu grupy w nawiasach jest niepotrzebny, ale nieszkodliwy. Aby to osiągnąć, używamy tego kodu:

vsXzJ"])"+R\,J
  X               Translate
   z              in the input
     "])"         the characters "])"
    J             which we will save to J to
             J    J
         +R\,     with each character mapped to itself plus a ",".
 s                Combine the list to a string.
v                  Evaluate as a Python literal.

To pozostawi dodatkowy ,na końcu łańcucha, który owinie cały obiekt w krotkę, ale jest to nieszkodliwe, ponieważ krotka zostanie zsumowana, a zatem będzie miała wartość równą jej elementowi.

Teraz, gdy ciąg jest analizowany, musimy znaleźć jego wartość. Odbywa się to za pomocą funkcji zdefiniowanej przez użytkownika y, która jest wywoływana w analizowanym obiekcie. funkcja jest zdefiniowana w następujący sposób:

L?*F+1yMbqb+YbsyMb
L                     Define a function, y(b), which returns the following:
 ?       qb+Yb        We form a ternary whose condition is whether the input, b,
                      equals the inputplus the empty list, Y. This is true if
                      and only if b is a list.
      yMb             If so, we start by mapping y over every element of b.
  *F+1                We then take the product of these values. The +1 ensures
                      that the empty list will return 1.
                yMb   Otherwise, we start by mapping y over every element of b.
               s      Then, we sum the results.
isaacg
źródło
@Jakube Racja, jednoargumentowe podsumowanie nie ma żadnego efektu.
isaacg
3

Emacs lisp, 94

Format wygląda bardzo zawstydzony, więc pomyślałem, że prosta transformacja może zadziałać:

(defun e()(format-replace-strings'(("("."(+")("["."(*")("]".")")))(eval(read(buffer-string))))

Format pośredni wygląda mniej więcej tak (na przykład w pytaniu):

(+(*)(+(+))(+(*)(*))(*(+))(*(+(*(*)(*))(*)(*))(+(*)(*))))

Pomaga nam fakt, że dodawanie i mnożenie już robi to, co chcemy, z pustą listą argumentów.

Degolfowany i interaktywny, dla Ciebie grającego w przyjemność:

(defun paren_eval()
  (interactive "*")
  (format-replace-strings '(("(" . "(+")
                            ("[" . "(*")
                            ("]" . ")")))
  (eval (read (buffer-string)))
)
Toby Speight
źródło
Powinienem był przeczytać więcej - rozwiązanie Common Lisp przyjmuje dokładnie to samo podejście!
Toby Speight
1
Potrzebujemy więcej odpowiedzi Emacsa Lispa !. Przy okazji, nie policzyłem, ale można trochę bardziej grać w golfa, używając lambda, biorąc ciąg znaków jako parametr i usuwając interactive (zamiast ciągu buforowego, użyj odczytu z ciągu).
coredump
2

Siatkówka , 111 bajtów

[\([](1+x)[]\)]
$1
\[]
1x
\(\)
x
(\[a*)1(?=1*x1*x)
$1a
a(?=a*x(1*)x)
$1
(\[1*x)1*x
$1
)`(\(1*)x(?=1*x)
$1
[^1]
<empty line>

Daje wynik jednostkowy.

Każda linia powinna przejść do własnego pliku, ale możesz uruchomić kod jako jeden plik z -sflagą. Na przykład:

> retina -s brackets <input_1
111111111

Wyjaśnienie nastąpi później.

randomra
źródło
2

Java, 349 znaków

Proste podejście rekurencyjne. Oczekuje, że ciąg będzie pierwszym argumentem używanym do wywołania programu.

import java.util.*;class K{int a=0,b;String c;public static void main(String[]a){K b=new K();b.c=a[0];System.out.print(b.a());}int a(){switch(c.charAt(a++)){case'(':b=0;for(int a:b())b+=a;break;case'[':b=1;for(int a:b())b*=a;}a++;return b;}List<Integer>b(){List d=new ArrayList();char c;while((c=this.c.charAt(a))!=']'&&c!=')')d.add(a());return d;}}

Rozszerzony:

import java.util.*;

class K {
    int a =0, b;
    String c;
    public static void main(String[] a){
        K b = new K();
        b.c = a[0];
        System.out.print(b.a());
    }
    int a(){
        switch (c.charAt(a++)){
            case '(':
                b =0;
                for (int a : b())
                    b += a;
                break;
            case '[':
                b =1;
                for (int a : b())
                    b *= a;
        }
        a++;
        return b;
    }
    List<Integer> b(){
        List d = new ArrayList();
        char c;
        while ((c= this.c.charAt(a)) != ']' && c != ')')
            d.add(a());
        return d;
    }
}
Numer jeden
źródło
2

Perl 5, 108

Sporządzono raczej jako tłumacz ustny niż przepisywanie i ewaluacja. Niezły pokaz, ale i tak fajnie się pisze.

push@s,/[[(]/?[(ord$_&1)x2]:do{($x,$y,$z,$t)=(@{pop@s},@{pop@s});
[$t?$x*$z:$x+$z,$t]}for<>=~/./g;say$s[0][0]

Bez golfa:

# For each character in the first line of stdin
for (<> =~ /./g) {
    if ($_ eq '[' or $_ eq '(') {
        # If it's an opening...
        # ord('[') = 91 is odd, ord('(') = 40 is even
        push @stack, [ ( ord($_) & 1) x 2 ];
        # so we will push [1, 1] on the stack for brackets and [0, 0] for parens.
        # one of these is used as the flag for which operator the context is, and
        # the other is used as the initial (identity) value.
    } else {
        # otherwise, assume it's a closing
        ($top_value, $top_oper) = @{ pop @stack };
        ($next_value, $next_oper) = @{ pop @stack };
        # merge the top value with the next-to-top value according to the
        # next-to-top operator. The top operator is no longer used.
        $new_value = $next_oper
            ? $top_value * $next_value
            : $top_value + $next_value
        push @stack, [ $new_value, $next_oper ];
    }
}

say $stack[0][0]; # print the value remaining on the stack.
Hobbs
źródło
2

Python, 99

Próbowałem różnych metod, ale najkrótszy, jaki mogłem uzyskać, był po prostu zamiennikiem i ewaluacją. Byłem mile zaskoczony, gdy stwierdziłem, że mogę zostawić wszystkie końcowe znaki ,, ponieważ Python może analizować, [1,2,]a końcowy przecinek końcowy po prostu stawia całość w krotce. Jedyna inna niż prosta część byłaby ord(c)%31%7do oddzielenia się różne znaki (ocenia się 2, 3, 1, 0na (, ), [, ]odpowiednio)

F=lambda s:eval(''.join(["],1),","reduce(int.__mul__,[","sum([","]),"][ord(c)%31%7]for c in s))[0]
KSab
źródło
1
To nie działa jako program, prawda? Pytanie dotyczy programu, więc nie sądzę, aby funkcja spełniała wymagania. Przynajmniej tak mówili mi ludzie, kiedy ostatni raz przesłałem funkcję, gdy w pytaniu było napisane „program”. :)
Reto Koradi
1

Java, 301

trochę inne podejście niż odpowiedź TheNumberOne, chociaż moja ma również charakter rekurencyjny. Dane wejściowe są pobierane z wiersza poleceń. Metoda void pozwala zaoszczędzić kilka bajtów podczas usuwania niepotrzebnych znaków.

enum E{I;String n;public static void main(String[]r){I.n=r[0];System.out.print(I.e());}int e(){int v=0;if(n.charAt(0)=='('){for(s("(");n.charAt(0)!=')';)v+=e();s(")");}else if(n.charAt(0)=='['){v=1;for(s("[");n.charAt(0)!=']';)v*=e();s("]");}return v;}void s(String c){n=n.substring(1+n.indexOf(c));}}

rozszerzony:

enum EvaluatingParenthesesAndBrackets{
    AsIntegers;
    String input;
    public static void main(String[]args){
        AsIntegers.input=args[0];
        System.out.print(AsIntegers.evaluate());
    }
    int evaluate(){
        int value=0;
        if(input.charAt(0)=='('){
            for(substringAfterChar("(");input.charAt(0)!=')';)
                value+=evaluate();
            substringAfterChar(")");
        }
        else if(input.charAt(0)=='['){
            value=1;
            for(substringAfterChar("[");input.charAt(0)!=']';)
                value*=evaluate();
            substringAfterChar("]");
        }
        return value;
    }
    void substringAfterChar(String character){
        input=input.substring(1+input.indexOf(character));
    }
}
Jack Ammo
źródło
1

Python, 117 110 109 bajtów

def C(s,p=[0]):
 m=r=s[p[0]]=='[';p[0]+=1
 while s[p[0]]in'[(':t=C(s,p);r=r*t*m+(r+t)*(1-m)
 p[0]+=1;return r

Jednym aspektem, z którym walczyłem, jest to, że funkcja ma zasadniczo dwie zwracane wartości: iloczyn / sumę i nową pozycję w ciągu. Ale potrzebuję funkcji, która zwraca tylko wynik, więc zwrócenie krotki nie działa. Ta wersja wykorzystuje argument „referencyjny” (lista z jednym elementem), aby przekazać pozycję z powrotem z funkcji.

Mam krótszą wersję (103 bajty), która używa zmiennej globalnej dla pozycji. Ale to zadziała tylko przy pierwszym połączeniu. A funkcja, która działa tylko raz, wydaje się nieco podejrzana. Nie jestem pewien, czy byłoby to dopuszczalne w przypadku golfa kodowego.

Algorytm jest prostą rekurencją. Wypróbowałem wiele wariantów wyrażenia aktualizującego produkt / sumę. Wymyśliłem kilka wersji, które były dokładnie tej samej długości, ale żadna z nich nie była krótsza.

Oczekiwałem, że podejście, które przekształci to w wyrażenie, które zostanie ocenione, prawdopodobnie wygra. Ale jak mówią: „iteracja jest człowiekiem, rekursja boska”.

Reto Koradi
źródło
Funkcje są teraz wyraźnie dozwolone :)
Calvin's Hobbies
@ Calvin'sHobbies Mam pytanie dotyczące zasad, o które ogólnie się zastanawiałem, ale które może się tutaj pojawić: jeśli rozwiązanie zostanie zaimplementowane jako funkcja, czy oznacza to, że funkcję można wywołać więcej niż raz w jednym przebiegu? Na przykład, jeśli użyłby zmiennej globalnej, która jest poprawnie zainicjowana tylko przy pierwszym wywołaniu, czy byłoby to ... błędne?
Reto Koradi,
@ Retro Powiedziałbym tak, to jest złe. Funkcja powinna działać dowolną liczbę razy bez jej ponownej interpretacji.
Calvin's Hobbies
1

Clojure - 66 bajtów

Zauważ, że ([] (()) ([] []) [()] [([[] []] [] []) ([] [])])jest to prawidłowy formularz Clojure. Więc:

#(letfn[(g[x](apply(if(list? x)+ *)(map g x)))](g(read-string %)))
  • To anonimowa funkcja polegająca na pobieraniu ciągu, czytaniu go i dawaniu g.
  • Zastosowanie ma gfunkcja lokalna +lub *wynik wywołania gpodelementów jej argumentów.
  • Podstawowy przypadek rekurencji jest nieco subtelny: jest osiągany, gdy występuje xw pustej sekwencji; (map g x)zwraca nili applyzwraca wartość neutralną dla operacji.
rdzeń rdzeniowy
źródło
0

JavaScript (ES6), 116 bajtów

s=>+[...s].reduce((t,c)=>((x=c==']')||c==')'?t[1].push(t.shift().reduce((a,b)=>x?a*b:a+b,+x)):t.unshift([]),t),[[]])
Ry-
źródło