Valutazione di parentesi e parentesi come numeri interi


20

Scrivi un programma che includa una stringa di quattro caratteri ()[]che soddisfi questi punti:

  • Ogni parentesi sinistra (ha una parentesi destra corrispondente ).
  • Ogni parentesi sinistra [ha una parentesi destra corrispondente ].
  • Le coppie di parentesi e parentesi corrispondenti non si sovrapporranno. es. [(])non è valido perché le parentesi corrispondenti non sono completamente contenute tra parentesi corrispondenti, né viceversa.
  • Il primo e l'ultimo carattere sono una coppia di parentesi o parentesi corrispondenti. Quindi ([]([]))e [[]([])]sono validi ma []([])non lo sono.

(Una grammatica per il formato di input è <input> ::= [<input>*] | (<input>*).)

Ogni coppia di parentesi e parentesi corrispondenti corrisponde a un numero intero non negativo:

  • I valori delle coppie tra parentesi corrispondenti sono tutti sommati . La corrispondenza vuota ()ha valore 0.
  • I valori delle coppie all'interno delle parentesi corrispondenti vengono moltiplicati . La corrispondenza vuota []ha valore 1.

(La somma o il prodotto di un numero è lo stesso numero.)

Ad esempio, ([](())([][])[()][([[][]][][])([][])])può essere suddiviso e valutato come 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>

Un altro esempio:

[([][][][][])([][][])([][][])(((((([][]))))))]    <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>

Il tuo programma deve valutare e stampare l'intero rappresentato dall'intera stringa di input. Si può presumere che l'input sia valido. Vince il codice più breve in byte.

Invece di un programma, è possibile scrivere una funzione che accetta una stringa e stampa o restituisce il numero intero.


Chiedere chiarimenti per conto dell'invio di Python: solo programma o le funzioni / il valore di ritorno sono a posto?
Sp3000,

Potrebbe essere utile modificare la domanda allora. In una domanda precedente, mi è stato detto che le funzioni non sono valide se si dice "scrivere un programma" nella domanda.
Reto Koradi,

Risposte:


11

CJam, 23

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

Con GRANDI crediti a Dennis! Provalo online

Spiegazione:

Il programma converte l'input in un'espressione CJam, quindi lo valuta.
[…]diventa […1]:*(aggiungi 1 e moltiplica)
(…)diventa […0]:+(aggiungi 0 e aggiungi)

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

1
La traslitterazione salva 4 byte:q"])(""1]:*0]:+["4/ers~
Dennis il

2
@Dennis whaaa! È folle, puoi farlo ??
aditsu,

3
Si sta chiedendo a me ? : P
Dennis,

4
@Dennis Come potrebbe il creatore di CJam sapere dell'esistenza di tale caratteristica ??
Ottimizzatore

8

Lisp comune - 98

(lambda(s)(eval(read-from-string(#1=ppcre:regex-replace-all"\\["(#1#"]"(#1#"\\("s"(+")")")"(*"))))
  1. Sostituisci (con(+
  2. Sostituisci [con(*
  3. Sostituisci ]con)
  4. Leggi da stringa
  5. Eval

Ciò richiede che la cl-ppcrelibreria sia caricata nell'immagine lisp corrente.

Spiegazione

Le funzioni *e +sono variabili e restituiscono il loro valore neutro quando non vengono forniti argomenti. Per i tuoi esempi, i moduli lisp valutati sono i seguenti:

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

e

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

Senza regex - 183 byte

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

Dai, Lisp - 16 byte (sperimentale)

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

Altre lingue sono così concise che sono tentato di creare il mio linguaggio golfistico basato sul Common Lisp, per manipolazioni delle stringhe più brevi. Al momento non ci sono specifiche e la funzione eval è la seguente:

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

test:

(cmon-lisp "+((<r*([<r)]<rRE" "([] [] ([] []))")
=> 4
  • c'è un argomento implicito chiamato se due pile, pe q.
  • i caratteri nel codice sorgente vengono inviati a p.
  • <: salta da pe spinge verso q.
  • r: sostituisce in s(deve essere una stringa) da caratteri in qa caratteri in p; il risultato è memorizzato in s; pe qsi svuotano.
  • R: letto dalla stringa s, memorizza il risultato in variabile s.
  • E: eval form s, store risultati in s.

1
Funyy come lisp è usato per fare qualcosa con parentesi qui.
Syd Kerckhove,

@SydKerckhove Il tuo commento mi fa venire in mente una risposta Clojure appropriata. Molte grazie!
coredump,

6

Pyth, 35 34 33 byte

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

Dimostrazione.

1 byte grazie a @Jakube.

Iniziamo analizzando l'input. Il formato di input è vicino a Python, ma non del tutto. Abbiamo bisogno di virgole dopo ogni gruppo tra parentesi o tra parentesi. La virgola alla fine di un gruppo tra parentesi non è necessaria, ma è innocua. A tale scopo, utilizziamo questo codice:

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.

Questo lascerà un extra ,alla fine della stringa, che avvolgerà l'intero oggetto in una tupla, ma questo è innocuo, perché la tupla verrà sommata e quindi avrà un valore uguale al suo elemento.

Ora che la stringa viene analizzata, dobbiamo trovare il suo valore. Questo viene fatto usando una funzione definita dall'utente y, che viene chiamata sull'oggetto analizzato. la funzione è definita come segue:

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.

@Jakube Bene, la somma unaria non ha alcun effetto.
Isaacg,

3

Emacs lisp, 94

Il formato sembra molto fluido, quindi ho pensato che una semplice trasformazione potesse funzionare:

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

Il formato intermedio ha un aspetto simile (per l'esempio nella domanda):

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

Siamo aiutati dal fatto che l'addizione e la moltiplicazione fanno già ciò che vogliamo con un elenco di argomenti vuoto.

Degolfato e interattivo, per il tuo piacere di suonare:

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

Avrei dovuto leggere più da vicino: la soluzione Common Lisp ha esattamente lo stesso approccio!
Toby Speight,

1
Abbiamo bisogno di più risposte Emacs Lisp !. A proposito, non ho contato ma potresti giocarci un po 'di più usando un lambda, prendendo una stringa come parametro e rimuovendo interactive (invece di buffer-string, usa read-from-string).
coredump,

2

Retina , 111 byte

[\([](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>

Fornisce output in unario.

Ogni riga dovrebbe andare al proprio file ma è possibile eseguire il codice come un file con il -sflag. Per esempio:

> retina -s brackets <input_1
111111111

La spiegazione arriva dopo.


2

Java, 349 caratteri

Un semplice approccio ricorsivo. Si aspetta che la stringa sia il primo argomento utilizzato per chiamare il programma.

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;}}

Allargato:

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;
    }
}

2

Perl 5, 108

Fatto come interprete piuttosto che riscrivere e valutare. Non è un grande spettacolo, ma divertente da scrivere comunque.

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]

Un-giocato a golf:

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

2

Python, 99

Ho provato una varietà di metodi, ma il più breve che potessi ottenere era sostanzialmente solo una sostituzione e una valutazione. Sono stato piacevolmente sorpreso di scoprire che avrei potuto lasciare tutti i messaggi finali ,, dato che Python può analizzare [1,2,]e la virgola finale finale mette tutto in una tupla. L'unica altra parte non-lineare sarebbe il ord(c)%31%7separare i diversi caratteri (che restituisce 2, 3, 1, 0per (, ), [, ]rispettivamente)

F=lambda s:eval(''.join(["],1),","reduce(int.__mul__,[","sum([","]),"][ord(c)%31%7]for c in s))[0]

1
Questo non funziona come un programma, vero? La domanda richiede un programma, quindi non credo che fornire una funzione soddisfi i requisiti. Almeno questo è quello che la gente mi ha detto l'ultima volta che ho inviato una funzione quando diceva "programma" nella domanda. :)
Reto Koradi,

1

Java, 301

un approccio un po 'diverso rispetto alla risposta di TheNumberOne, anche se la mia è anche di natura ricorsiva. L'input viene preso dalla riga di comando. Il metodo void salva alcuni byte quando si rimuovono i caratteri non più necessari.

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));}}

allargato:

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));
    }
}

1

Python, 117 110 109 109 byte

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

Un aspetto con cui stavo lottando è che la funzione ha fondamentalmente due valori di ritorno: il prodotto / somma e la nuova posizione nella stringa. Ma ho bisogno di una funzione che restituisca solo il risultato, quindi restituire una tupla non funziona. Questa versione utilizza un argomento "di riferimento" (elenco con un elemento), per passare indietro la posizione dalla funzione.

Ho una versione più breve (103 byte) che utilizza una variabile globale per la posizione. Ma funzionerà solo alla prima chiamata. E una funzione che funziona solo una volta sembra un po 'sospetta. Non sono sicuro se sarebbe accettabile per il codice golf.

L'algoritmo è semplice ricorsione. Ho provato una serie di varianti per l'espressione che aggiorna il prodotto / somma. Ho escogitato alcune versioni che erano esattamente della stessa lunghezza, ma nessuna più corta.

Mi aspettavo che l'approccio che lo trasforma in un'espressione che viene valutata probabilmente vincerebbe. Ma come si suol dire: "iterare è umano, fare ricorso divino".


Funzioni ora esplicitamente consentite :)
Hobby di Calvin il

@ Calvin'sHobbies Hai una domanda sulle regole che mi chiedevo generalmente, ma che potrebbe entrare in gioco qui: se una soluzione è implementata come una funzione, ciò implica che la funzione può essere chiamata più di una volta in una singola corsa? Ad esempio, se utilizzasse una variabile globale inizializzata correttamente solo alla prima chiamata, sarebbe ... sbagliato?
Reto Koradi,

@Retro Direi di sì, è sbagliato. La funzione dovrebbe funzionare un numero qualsiasi di volte senza reinterpretarla.
Calvin's Hobbies,

1

Clojure - 66 byte

Si noti che ([] (()) ([] []) [()] [([[] []] [] []) ([] [])])è un modulo Clojure valido. Così:

#(letfn[(g[x](apply(if(list? x)+ *)(map g x)))](g(read-string %)))
  • Questa è una funzione anonima che prende una stringa, la legge e la dà g.
  • La gfunzione locale si applica +o *al risultato dell'invocazione di gsotto-elementi dei suoi argomenti.
  • Il caso base della ricorsione è un po 'sottile: si raggiunge xin una sequenza vuota;(map g x)ritorna nile applyrestituisce il valore neutro per l'operazione.

0

JavaScript (ES6), 116 byte

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),[[]])
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.