返回信息流假设已经分割好了,输入是一个list,里面可能有数,也可能有运算符(用字符串表示)。运算符有加减乘除模和乘方,没有括号。请写一个函数求这个表达式的值。请优先考虑使代码长度最短而不是效率最高。不许使用eval和exec。
例子:
def eval_expr(e):
....
>>> eval_expr([1, '+', 1])
2
>>> eval_expr([1, '-', 2, '*', 3, '**', 3, '/' 3]) # 先乘方,再乘除模,再加减
-17
>>> eval_expr([12, '%', 5])
2
>>> eval_expr([2, '**', 3])
8
>>> eval_expr([3, '-', 2, '-', 1]) # 同级运算,加减、乘除模都是从左到右
0
>>> eval_expr([3, '**', 3, '**', 3]) # 但乘方是右结合的
7625597484987
这是一条镜像帖。来源:北邮人论坛 / python / #12920同步于 2016/3/25
该镜像源已超过 30 天没有更新,可能在源站已被删除。
Python机器人发帖
挑战:来做计算器
nuanyangyang
2016/3/25镜像同步30 回复
订阅后,新回复会通过你的通知中心匿名送达。
9 条回复
【 在 Dogless 的大作中提到: 】
: version 0
: [code=py]
: def eval_expr(e):
: ...................
尼玛,好暴力的e[::-1]
【 在 Dogless 的大作中提到: 】
: version 2
: [code=py]
: def eval_expr(e):
: ...................
试试这个输入:[3, "-", 2, "+", 1]
def eval_expr(e):
return reduce(lambda s, x: s[:-1] + [s[-1] + x[1] if x[0] == '+' else s[-1] - x[1]] if x[0] == '+' or x[0] == '-' else s + x, *(lambda e2: (([e2[i], e2[i+1]] for i in xrange(1, len(e2), 2)), [e2[0]]))(reduce(lambda s, x: s[:-1] + [s[-1] * x[1] if x[0] == '*' else s[-1] / x[1] if x[0] == '/' else s[-1] % x[1]] if x[0] == '*' or x[0] == '/' or x[0] == '%' else s + x, *(lambda e1: (([e1[i], e1[i+1]] for i in xrange(1, len(e1), 2)), [e1[0]]))(reduce(lambda s, x: s[:-1] + [x[1] ** s[-1]] if x[0] == '**' else s + x, ([e[i], e[i-1]] for i in xrange(len(e)-2, -1, -2)), [e[-1]])[::-1]))))[0]
除了压进了一行以外好像一点也不短……又拆开写了一遍
OPS = [('+', '-'), ('*', '/', '%'), ('**')]
def exec_op(op, x, y):
if op == '**':
return x ** y
if op == '*':
return x * y
if op == '/':
return x / y
if op == '%':
return x % y
if op == '+':
return x + y
if op == '-':
return x - y
def eval_once(e, lvl):
if lvl == 2:
e = e[::-1]
s = [e[0]]
for i in xrange(1, len(e), 2):
if e[i] in OPS[lvl]:
s[-1] = exec_op(e[i], s[-1], e[i+1])
else:
s = s + [e[i], e[i+1]]
return s[::-1] if lvl == 2 else s
def eval_expr(e):
return eval_once(eval_once(eval_once(e, 2), 1), 0)[0]
另外一个不说人话版
def exec_op(op, x, y):
if op == '**':
return x ** y
if op == '*':
return x * y
if op == '/':
return x / y
if op == '%':
return x % y
if op == '+':
return x + y
if op == '-':
return x - y
def split(lst, seps):
r = [[]]
for i in lst:
if i in seps:
r += [i, []]
else:
r[-1].append(i)
return r
def chunk_with_plus(a):
return zip(['+'] + a[1::2], a[0::2])
def eval_expr(e):
return reduce(lambda s0, x0: exec_op(x0[0], s0, reduce(lambda s1, x1: exec_op(x1[0], s1, reduce(lambda s2, x2: x2 ** s2, x1[1][-3::-2], x1[1][-1])), chunk_with_plus(x0[1]), 0)), chunk_with_plus([split(l1, set(('*', '/', '%'))) if isinstance(l1, list) else l1 for l1 in (split(e, set(('+', '-'))))]), 0)
把这一版展开
def exec_op(op, x, y):
if op == '**':
return x ** y
if op == '*':
return x * y
if op == '/':
return x / y
if op == '%':
return x % y
if op == '+':
return x + y
if op == '-':
return x - y
def split(lst, seps):
r = [[]]
for i in lst:
if i in seps:
r += [i, []]
else:
r[-1].append(i)
return r
def eval_lvl2(e):
return reduce(lambda s, x: x ** s, e[-3::-2], e[-1])
def eval_lvl1(e):
e = split(e, set(('*', '/', '%')))
return reduce(lambda s, x: exec_op(x[0], s, eval_lvl2(x[1])), zip(e[1::2], e[2::2]), eval_lvl2(e[0]))
def eval_expr(e):
e = split(e, set(('+', '-')))
return reduce(lambda s, x: exec_op(x[0], s, eval_lvl1(x[1])), zip(e[1::2], e[2::2]), eval_lvl1(e[0]))
【 在 glazard 的大作中提到: 】
: ...................
>>> eval_expr([2,"**",3])
9
展开的时候把两个参数弄倒了……
OPS = [('+', '-'), ('*', '/', '%'), ('**')]
def exec_op(op, x, y):
if op == '**':
return x ** y
if op == '*':
return x * y
if op == '/':
return x / y
if op == '%':
return x % y
if op == '+':
return x + y
if op == '-':
return x - y
def eval_once(e, lvl):
if lvl == 2:
e = e[::-1]
s = [e[0]]
for i in xrange(1, len(e), 2):
if e[i] in OPS[lvl]:
if lvl == 2:
s[-1] = exec_op(e[i], e[i+1], s[-1])
else:
s[-1] = exec_op(e[i], s[-1], e[i+1])
else:
s = s + [e[i], e[i+1]]
return s[::-1] if lvl == 2 else s
def eval_expr(e):
return eval_once(eval_once(eval_once(e, 2), 1), 0)[0]
print(eval_expr([2,"**",3]))
另外补了一个比较正常的版本
OPS = (set(('+', '-')), set(('*', '/', '%')), set(('**',)))
def exec_op(op, x, y):
if op == '**':
return x ** y
if op == '*':
return x * y
if op == '/':
return x / y
if op == '%':
return x % y
if op == '+':
return x + y
if op == '-':
return x - y
def eval_lvl(e, lvl, right=False):
if lvl == 3:
return e[0]
for i in xrange(1, len(e) - 1, 2) if right else xrange(len(e) - 2, 0, -2):
op = e[i]
if op in OPS[lvl]:
if right:
return exec_op(op, eval_lvl(e[:i], lvl+1, lvl==1), eval_lvl(e[i+1:], lvl, right))
else:
return exec_op(op, eval_lvl(e[:i], lvl, right), eval_lvl(e[i+1:], lvl+1, lvl==1))
return eval_lvl(e, lvl+1, lvl==1)
def eval_expr(e):
return eval_lvl(e, 0, False)
【 在 nuanyangyang 的大作中提到: 】
:
: >>> eval_expr([2,"**",3])
: 9
: ...................