我正在编写一个Python 3脚本,用于制作林业木材计数表。
工人们将向计算机操作员标记每棵树的日志中的物种,直径和高度。然后,计算机操作员将输入如下命令:
OAK 14 2
表示该程序应该增加直径为14英寸,高度为2个对数的橡树的数量。
但是,工人有时也会同时调用多个相同类型的树。所以程序也必须能够处理这个命令:
OAK 16 1 2
这意味着我们将计数增加了两倍。
我设置解析器的方式是:
key=cmdtup[0]+"_"+cmdtup[1]+"_"+cmdtup[2]
try:
trees[key]=int(trees[key])+int(cmdtup[3])
except KeyError:
trees[key]=int(cmdtup[3])
except IndexError:
trees[key]=int(trees[key])+1
如果程序被命令存储它之前没有存储的树,则KeyError将关闭,并且处理程序将设置dict条目而不是增加它。如果省略第三个参数,则会引发IndexError,并且处理程序会将其视为第三个参数为1。
但是,如果我们同时处于这两种情况,就会出现问题;程序还没有听说过橡树,操作员没有指定计数。 KeyError关闭,但随后生成了自己的IndexError,并且当异常处理程序中发生异常时,Python不喜欢它。
我认为最简单的方法是简单地删除一个或另一个,并以其他方式完成其功能。不过,我想知道是否有更优雅的Pythonic方法。有吗?
答案 0 :(得分:0)
我会做这样的事情:
def parse(cmd, trees):
res = cmd.split() # split the string by spaces, yielding a list of strings
if len(res) == 3: # if we got 3 parameters, set the fourth to 1
res.append(1)
for i in range(1,4): # convert parameters 1-3 to integers
res[i] = int(res[i])
key = tuple(res[x] for x in range(3)) # convert list to tuple, as lists cannot be dictionary indexes
trees[key] = trees.get(key,0) + res[3] # increase the number of entries, creating it if needed
trees={}
# test data
parse("OAK 14 2", trees)
parse("OAK 16 1 2", trees)
parse("OAK 14 2", trees)
parse("OAK 14 2", trees)
# print result
for tree in trees:
print(tree, "=", trees[tree])
产生
('OAK', 16, 1) = 2
('OAK', 14, 2) = 3
一些注意事项:
答案 1 :(得分:0)
如果密钥不在字典中,您可以使用collections.Counter
,它返回0而不是KeyError
。
<强> Counter Documentation: 强>
Counter
个对象有一个字典界面,除了它们为丢失的项目返回零计数而不是提出KeyError
这样的事情:
from collections import Counter
counts = Counter()
def update_counts(counts, cmd):
cmd_list = cmd.split()
if len(cmd_list) == 3:
tree = tuple(cmd_list)
n = 1
else:
*tree, n = tuple(cmd_list)
counts[tree] += n
同样的说明适用于uselpa的答案。 Counter
的另一个好处是,如果您想要查看每周计数,您只需执行sum(daily_counts)
之类的操作。
Counter
的效果会更好:
from collections import Counter
from itertools import repeat
raw_commands = get_commands() # perhaps read a file
command_lists = [c.split() for c in raw_commands]
counts = Counter(parse(command_lists))
def parse(commands):
for c in commands:
if len(c) == 3:
yield tuple(c)
elif len(c) == 4
yield from repeat(tuple(c[0:2]), times=c[3])
从那里你可以使用上面的update_counts
函数添加新树,或者你可以开始在另一个文本文件中收集命令,然后在第二天生成第二个Counter
对象,下一个一周等等。
答案 2 :(得分:0)
最后,最好的方法是简单地删除IndexError处理程序,将cmdtup更改为列表,然后插入以下内容:
if len(cmdtup) >= 3:
cmdtup.append(1)