Evaluación de paréntesis y corchetes como enteros

20

Escriba un programa que tome una cadena de los cuatro caracteres ()[]que satisfaga estos puntos:

  • Cada paréntesis izquierdo (tiene un paréntesis derecho coincidente ).
  • Cada soporte izquierdo [tiene un soporte derecho a juego ].
  • Los pares de paréntesis y corchetes no se superpondrán. por ejemplo, [(])no es válido porque los corchetes coincidentes no están completamente contenidos en los paréntesis coincidentes, ni viceversa.
  • El primer y el último carácter son un par de paréntesis o paréntesis coincidentes. Entonces ([]([]))y [[]([])]son válidos pero []([])no lo son.

(Una gramática para el formato de entrada es <input> ::= [<input>*] | (<input>*)).

Cada par de paréntesis y paréntesis coincidentes se evalúa como un entero no negativo:

  • Todos los valores de pares dentro de paréntesis coincidentes se suman . La coincidencia vacía ()tiene valor 0.
  • Los valores de pares dentro de paréntesis coincidentes se multiplican . La coincidencia vacía []tiene valor 1.

(La suma o producto de un número es ese mismo número).

Por ejemplo, ([](())([][])[()][([[][]][][])([][])])se puede desglosar y evaluar como 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>

Otro ejemplo:

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

Su programa necesita evaluar e imprimir el número entero representado por toda la cadena de entrada. Puede asumir que la entrada es válida. El código más corto en bytes gana.

En lugar de un programa, puede escribir una función que tome una cadena e imprima o devuelva el entero.

Pasatiempos de Calvin
fuente
Pidiendo aclaraciones en nombre del envío de Python: ¿solo el programa o las funciones / valor de retorno están bien?
Sp3000
Podría ser bueno editar la pregunta entonces. En una pregunta anterior, me dijeron que las funciones no son válidas si dice "escribir un programa" en la pregunta.
Reto Koradi

Respuestas:

11

CJam, 23

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

¡Con GRANDES créditos para Dennis! Pruébalo en línea

Explicación:

El programa convierte la entrada en una expresión CJam y luego la evalúa.
[…]se convierte […1]:*(agrega 1 y multiplica) se
(…)convierte […0]:+(agrega 0 y agrega)

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
fuente
1
La transliteración ahorra 4 bytes:q"])(""1]:*0]:+["4/ers~
Dennis
2
@Dennis whaaa! Eso es una locura, ¿puedes hacer eso?
aditsu
3
Usted está pidiendo a ? : P
Dennis
44
@Dennis ¿Cómo sabría el creador de CJam sobre la existencia de tal característica?
Optimizador
8

Lisp común - 98

(lambda(s)(eval(read-from-string(#1=ppcre:regex-replace-all"\\["(#1#"]"(#1#"\\("s"(+")")")"(*"))))
  1. Reemplazar (por(+
  2. Reemplazar [por(*
  3. Reemplazar ]por)
  4. Leer de la cadena
  5. Eval

Esto requiere que la cl-ppcrebiblioteca se cargue en la imagen lisp actual.

Explicación

Funciona *y +es variable y devuelve su valor neutral cuando no se le dan argumentos. Para sus ejemplos, la forma de lisp evaluada es la siguiente:

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

y

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

Sin expresiones regulares: 183 bytes

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

Vamos, Lisp - 16 bytes (experimental)

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

Otros idiomas son tan concisos que me siento tentado a hacer mi propio lenguaje de golf basado en Common Lisp, para manipulaciones de cuerdas más cortas. Actualmente no hay especificación, y la función eval es la siguiente:

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

Pruebas:

(cmon-lisp "+((<r*([<r)]<rRE" "([] [] ([] []))")
=> 4
  • hay un argumento implícito llamado sy dos pilas, py q.
  • los caracteres en el código fuente son empujados a p.
  • <: aparece py empuja hacia q.
  • r: reemplaza s(debe ser una cadena) de caracteres en qcaracteres p; el resultado se almacena en s; py qse vacían
  • R: lee de la cadena s, almacena el resultado en una variable s.
  • E: evalúe la forma s, almacene el resultado en s.
volcado de memoria
fuente
1
Funyy cómo se usa lisp para hacer algo con corchetes aquí.
Syd Kerckhove
@SydKerckhove Tu comentario solo me hace pensar en una respuesta Clojure adecuada. ¡Muchas gracias!
coredump
6

Pyth, 35 34 33 bytes

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

Demostración.

1 byte gracias a @Jakube.

Comenzamos analizando la entrada. El formato de entrada está cerca de Python, pero no del todo. Necesitamos comas después de cada grupo entre paréntesis o entre corchetes. La coma al final de un grupo entre corchetes es innecesaria, pero inofensiva. Para lograr esto, usamos este código:

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.

Esto dejará un extra ,al final de la cadena, que envolverá todo el objeto en una tupla, pero esto es inofensivo, porque la tupla se sumará y tendrá un valor igual a su elemento.

Ahora que la cadena se analiza, debemos encontrar su valor. Esto se realiza mediante una función definida por el usuario y, que se llama en el objeto analizado. la función se define de la siguiente manera:

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
fuente
@Jakube Derecha, la suma unaria no tiene ningún efecto.
isaacg
3

Emacs lisp, 94

El formato se ve muy lispy, así que pensé que una transformación simple podría funcionar:

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

El formato intermedio se parece a (para el ejemplo en la pregunta):

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

Nos ayuda el hecho de que la suma y la multiplicación ya hacen lo que queremos con una lista de argumentos vacía.

Degolfed, e interactivo, para que juegues placer:

(defun paren_eval()
  (interactive "*")
  (format-replace-strings '(("(" . "(+")
                            ("[" . "(*")
                            ("]" . ")")))
  (eval (read (buffer-string)))
)
Toby Speight
fuente
Debería haber leído más de cerca: ¡la solución Common Lisp adopta exactamente el mismo enfoque!
Toby Speight
1
¡Necesitamos más respuestas de Emacs Lisp !. Por cierto, no conté, pero podrías jugar un poco más usando una lambda, tomando una cuerda como parámetro y eliminandointeractive (en lugar de buffer-string, usa read-from-string).
coredump
2

Retina , 111 bytes

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

Da salida en unario.

Cada línea debe ir a su propio archivo, pero puede ejecutar el código como un archivo con la -sbandera. P.ej:

> retina -s brackets <input_1
111111111

La explicación viene después.

randomra
fuente
2

Java, 349 caracteres

Un enfoque recursivo simple. Espera que la cadena sea el primer argumento utilizado para llamar al programa.

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

Expandido:

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;
    }
}
El numero uno
fuente
2

Perl 5, 108

Hecho como intérprete en lugar de reescribir y evaluar. No es una gran muestra, pero es divertido escribir de todos modos.

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]

Sin 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.
hobbs
fuente
2

Python, 99

Probé una variedad de métodos, pero lo más corto que pude obtener fue básicamente un reemplazo y evaluación. Me sorprendió gratamente descubrir que podía dejar todos los mensajes finales ,, ya que Python puede analizar [1,2,]y la coma final final simplemente pone todo en una tupla. La única otra parte no sencilla sería la ord(c)%31%7de separar los diferentes personajes (que se evalúa como 2, 3, 1, 0para (, ), [, ]respectivamente)

F=lambda s:eval(''.join(["],1),","reduce(int.__mul__,[","sum([","]),"][ord(c)%31%7]for c in s))[0]
KSab
fuente
1
Esto no funciona como un programa, ¿verdad? La pregunta solicita un programa, por lo que no creo que proporcionar una función cumpla con los requisitos. Al menos eso es lo que la gente me dijo la última vez que presenté una función cuando decía "programa" en la pregunta. :)
Reto Koradi
1

Java, 301

un enfoque un poco diferente a la respuesta de TheNumberOne, aunque la mía también es de naturaleza recursiva. La entrada se toma de la línea de comando. El método nulo guarda algunos bytes al eliminar los caracteres que ya no son necesarios.

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

expandido:

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 munición
fuente
1

Python, 117 110 109 bytes

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 aspecto con el que estaba luchando es que la función básicamente tiene dos valores de retorno: el producto / suma y la nueva posición en la cadena. Pero necesito una función que solo devuelva el resultado, por lo que devolver una tupla no funciona. Esta versión usa un argumento de "referencia" (lista con un elemento), para pasar la posición de regreso de la función.

Tengo una versión más corta (103 bytes) que usa una variable global para la posición. Pero eso solo funcionará en la primera llamada. Y una función que solo funciona una vez parece un poco sospechosa. No estoy seguro de si sería aceptable para el código de golf.

El algoritmo es la recursividad directa. Intenté varias variaciones para la expresión que actualiza el producto / suma. Se me ocurrieron algunas versiones que tenían exactamente la misma longitud, pero ninguna más corta.

Esperaba que el enfoque que convierte esto en una expresión que se evalúa probablemente gane. Pero como dicen: "iterar es humano, recurrir a lo divino".

Reto Koradi
fuente
Funciones ahora explícitamente permitidas :)
Calvin's Hobbies
@ Calvin'sHobbies Tengo una pregunta sobre reglas que generalmente me preguntaba, pero que podría entrar en juego aquí: si una solución se implementa como una función, ¿esto implica que la función se puede llamar más de una vez en una sola ejecución? Por ejemplo, si usa una variable global que solo se inicializa correctamente en la primera llamada, ¿sería ... incorrecto?
Reto Koradi
@Retro Yo diría que sí, está mal. La función debería funcionar varias veces sin reinterpretarla.
Calvin's Hobbies
1

Clojure - 66 bytes

Tenga en cuenta que ([] (()) ([] []) [()] [([[] []] [] []) ([] [])])es un formulario válido de Clojure. Entonces:

#(letfn[(g[x](apply(if(list? x)+ *)(map g x)))](g(read-string %)))
  • Esta es una función anónima que toma una cadena, la lee y se la da g.
  • La gfunción local se aplica +o *al resultado de la invocación deg en sub-elementos de sus argumentos.
  • El caso base de la recursión es un poco sutil: se alcanza cuando está xen una secuencia vacía; (map g x)devuelve nily applydevuelve el valor neutral para la operación.
volcado de memoria
fuente
0

JavaScript (ES6), 116 bytes

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-
fuente