reduce函数使用困惑:罗马数字转整数代码报KeyError求助
罗马数字转整数reduce实现的KeyError问题解析
我正在学习reduce函数,起初觉得它简单易懂。尝试实现罗马数字转整数的功能,写了如下代码:
rit = {'I': 1, 'V': 5, 'X': 10, 'L': 50, 'C': 100, 'D': 500, 'M': 1000} reduce(lambda x, y: rit[x] + rit[y], s)
运行后出现KeyError报错:
KeyError: 2 return reduce(lambda x, y: rit[x] + rit[y], list(s)) Line 4 in <lambda> (Solution.py) return reduce(lambda x, y: rit[x] + rit[y], list(s)) Line 4 in romanToInt (Solution.py) ret = Solution().romanToInt(param_1) Line 28 in _driver (Solution.py) _driver() Line 39 in <module> (Solution.py)
原本期望通过字典映射求和得到结果,却出现该报错,请问原因是什么?
问题原因
reduce函数的执行逻辑是:第一次调用lambda时,取序列s的前两个元素作为x和y,计算rit[x]+rit[y]得到一个整数结果;第二次调用lambda时,x会替换成上一次计算出的整数,而y是序列的下一个字符元素。此时用rit[x]去字典中查找,x是整数类型,但字典的键是罗马字符,自然找不到匹配项,所以抛出KeyError。
比如报错里的KeyError:2,说明第一次计算得到了整数2,第二次拿这个整数去字典查询,不存在对应键,直接触发报错。
修正方案
要正确用reduce实现罗马数字转整数,需要兼顾罗马数字的规则(小值在大值左侧时做减法,如IV=4=5-1),同时让reduce的累计值保持可正确处理的状态。示例写法如下:
from functools import reduce rit = {'I': 1, 'V': 5, 'X': 10, 'L': 50, 'C': 100, 'D': 500, 'M': 1000} def romanToInt(s): # 初始值取第一个字符的数值,后续迭代处理剩余字符 return reduce(lambda total, curr_char: total + (rit[curr_char] if rit[curr_char] <= rit[s[total_idx]] else rit[curr_char] - 2*rit[s[total_idx]]), s[1:], rit[s[0]])
或者用更清晰的方式,让reduce累计值同时保存总和与前一个字符的数值:
from functools import reduce rit = {'I': 1, 'V': 5, 'X': 10, 'L': 50, 'C': 100, 'D': 500, 'M': 1000} def romanToInt(s): def update(total_prev, curr_char): total, prev_val = total_prev curr_val = rit[curr_char] # 小值在前则修正总和,否则直接累加 if curr_val > prev_val: return (total - prev_val + curr_val - prev_val, curr_val) else: return (total + curr_val, curr_val) if not s: return 0 initial_total = rit[s[0]] return reduce(update, s[1:], (initial_total, rit[s[0]]))[0]
内容的提问来源于stack exchange,提问作者Ecce
相关产品推荐
相关产品推荐

