将括号和方括号评估为整数


20

编写一个程序,()[]使用满足以下要求的四个字符组成的字符串:

  • 每个左括号(都有一个匹配的右括号)
  • 每个左括号[都有一个匹配的右括号]
  • 配对的括号和方括号不会重叠。例如[(])是无效的,因为匹配括号没有完全包含在匹配括号中,反之亦然。
  • 第一个和最后一个字符是一对匹配的括号或括号。所以([]([]))[[]([])]是有效的,但[]([])不是。

(输入格式的语法<input> ::= [<input>*] | (<input>*)。)

每对匹配的括号和括号都得出一个非负整数:

  • 匹配括号内的对值全部相加。空匹配()具有价值0
  • 匹配括号内的对值全部相乘。空匹配[]具有价值1

(一个数字的总和乘积是相同的数字。)

例如,([](())([][])[()][([[][]][][])([][])])可以细分并评估为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>

另一个例子:

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

您的程序需要评估并打印由整个输入字符串表示的整数。您可以假定输入有效。以字节为单位的最短代码获胜。

您可以编写一个接受字符串并打印或返回整数的函数,而不是程序。


代表Python提交者进行澄清:仅程序,还是函数/返回值可以吗?
Sp3000

然后可能会很好地编辑问题。在上一个问题中,有人告诉我如果函数在问题中说“编写程序”,则该函数无效。
Reto Koradi

Answers:


11

CJam,23岁

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

用丹尼斯的大信用!在线尝试

说明:

程序将输入转换为CJam表达式,然后对其求值。
[…]变成[…1]:*(追加1并乘以)
(…)变成[…0]:+(追加0并加)

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
音译节省4个字节:q"])(""1]:*0]:+["4/ers~
丹尼斯2015年

2
@丹尼斯·哇!太疯狂了,你可以做到吗?
aditsu 2015年

3
在问吗?:P
丹尼斯

4
@Dennis CJam的创建者将如何知道该功能的存在?
Optimizer

8

普通Lisp-98

(lambda(s)(eval(read-from-string(#1=ppcre:regex-replace-all"\\["(#1#"]"(#1#"\\("s"(+")")")"(*"))))
  1. 替换((+
  2. 替换[(*
  3. 替换])
  4. 从字符串读取
  5. 评估

这要求将cl-ppcre库加载到当前的Lisp映像中。

说明

函数*+是可变参数,并且在不指定参数的情况下返回其中性值。对于您的示例,评估后的lisp表单如下:

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

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

没有正则表达式-183字节

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

C'mon,Lisp-16个字节(实验性)

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

其他语言非常简洁,我很想基于Common Lisp创建自己的高尔夫语言,以便进行更短的字符串操作。当前没有任何规范,eval函数如下:

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

测试:

(cmon-lisp "+((<r*([<r)]<rRE" "([] [] ([] []))")
=> 4
  • 有一个称为的隐式参数s和两个堆栈,pq
  • 源代码中的字符被推送到p
  • <:从弹出p并推向q
  • r:在内容替换s(必须是一个字符串)从字符q到在本地字符p; 结果存储在s; pq清空。
  • R:从字符串读取s,将结果存储在变量中s
  • E:计算形式s,将结果存储在s

1
有趣的是,在这里,如何用Lisp来做带括号的事情。
Syd Kerckhove 2015年

@SydKerckhove您的评论只是让我想到适当的Clojure答案。非常感谢!
coredump

6

Pyth,35 34 33字节

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

示范。

1个字节,感谢@Jakube。

我们首先分析输入。输入格式接近Python,但不完全相同。每个括号或方括号后都需要逗号。方括号末尾的逗号是不必要的,但无害。为此,我们使用以下代码:

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.

这将,在字符串的末尾留下一个多余的字符串,它将整个对象包装在一个元组中,但这是无害的,因为该元组将被求和,因此其值等于其元素。

现在已经解析了字符串,我们必须找到它的值。这是使用用户定义的函数来完成的y,该函数在已解析的对象上调用。该函数定义如下:

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对,一元求和无效。
isaacg 2015年

3

Emacs Lisp,94岁

格式看起来很花哨,所以我认为可以进行简单的转换:

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

中间格式类似于(对于问题中的示例):

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

一个空的参数列表已经满足了加法和乘法的要求,这为我们提供了帮助。

脱胶,互动,为您带来娱乐乐趣:

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

我应该仔细阅读-Common Lisp解决方案采用完全相同的方法!
Toby Speight 2015年

1
我们需要更多Emacs Lisp答案!顺便说一句,我没有数,但是您可以通过使用lambda,将字符串作为参数并删除interactive (而不是使用缓冲字符串,而使用read-from-string)来打高尔夫球。
coredump

2

视网膜,111字节

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

给出一元输出。

每一行都应转到其自己的文件,但是您可以将代码作为带有-s标志的一个文件运行。例如:

> retina -s brackets <input_1
111111111

稍后再进行解释。


2

Java,349个字符

一种简单的递归方法。期望该字符串是用于调用程序的第一个参数。

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

展开:

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

做为解释器,而不是重写和评估。这不是一个很好的展示,但是无论如何还是很有趣。

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]

未打高尔夫球:

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

我尝试了多种方法,但我能得到的最短的方法基本上只是替换和评估。当我发现可以留下所有结尾的,s时,我感到很惊讶,因为Python可以解析[1,2,],最后的逗号将整个内容放在一个元组中。唯一的其他非直接的部分将是ord(c)%31%7到单独出来的不同的字符(它的计算结果为2310()[]分别地)

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

1
这不能用作程序,对吗?这个问题需要一个程序,所以我认为提供一个功能不能满足要求。至少那是人们上次告诉我的,当我在问题中说“程序”时,我提交了一个函数。:)
Reto Koradi

1

爪哇301

尽管Themine本质上也是递归的,但与TheNumberOne的回答有些不同。输入来自命令行。删除不再需要的字符时,void方法将节省一些字节。

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

扩展:

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字节

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

我苦苦挣扎的一方面是该函数基本上有两个返回值:乘积/和,以及字符串中的新位置。但是我需要一个仅返回结果的函数,因此返回元组不起作用。此版本使用“引用”参数(带有一个元素的列表)将位置从函数传回。

我有一个较短的版本(103字节),该位置使用全局变量。但这仅适用于首次通话。一个只能使用一次的函数似乎有点混乱。不确定代码高尔夫是否可以接受。

该算法是直接的递归。对于更新乘积/和的表达式,我尝试了多种变体。我想出了一些长度完全相同的版本,但没有一个更短。

我有点期望将其转换为可被评估的表达式的方法可能会获胜。但是正如他们所说:“迭代是人类,是递归神圣。”


现在已明确允许使用功能:)
卡尔文的爱好

@ Calvin'sHobbies有一个我通常想知道的规则问题,但这可能在这里起作用:如果将解决方案实现为函数,这是否意味着该函数可以在一次运行中被多次调用?例如,如果它使用仅在第一次调用时正确初始化的全局变量,那是...错误吗?
Reto Koradi

@Retro我会说是的,这是错误的。该函数应工作多次,而无需重新解释它。
加尔文的爱好

1

Clojure-66个字节

请注意,这([] (()) ([] []) [()] [([[] []] [] []) ([] [])])是有效的Clojure表单。所以:

#(letfn[(g[x](apply(if(list? x)+ *)(map g x)))](g(read-string %)))
  • 这是一个匿名函数,接受一个字符串,读取该字符串并提供给g
  • 局部g函数适用于+*调用的结果g在它的参数子元素。
  • 递归的基本情况有些微妙:x在空序列中可以达到;(map g x)返回nil,并apply返回操作的中性值。

0

JavaScript(ES6),116个字节

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),[[]])
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.