这将更容易使用csv
模块来完成。例如:
with open('highscores.txt', 'rb') as f:
reader = csv.reader(f)
scores = list(reader)
现在,scores
将是一个包含 10 个列表的列表,每个列表有 4 个值。
如果你愿意,你可以做同样的事情split
,但你必须确保所有的细节都是正确的,比如从每行的末尾剥离换行符(在非平凡的 CSV 文件中,细节会变得更加复杂):
with open('highscores.txt', 'rb') as f:
scores = [line.strip().split(',') for line in f]
现在,您可以使用每个步骤的单个理解或函数调用一次转换该列表一个步骤。这种“声明式编程”,你只需说出你想对值做什么,而不是写出一个循环并交错所有步骤,可以让你的生活更轻松。
如果你只想要最后一列,理解可以做到这一点:
with open('highscores.txt', 'rb') as f:
reader = csv.reader(f)
scores = [row[-1] for row in reader]
如果您希望它们转换为整数:
with open('highscores.txt', 'rb') as f:
reader = csv.reader(f)
scores = (row[-1] for row in reader)
intscores = [int(score) for score in scores]
…尽管在这种情况下将两个步骤合并在一起很简单:
with open('highscores.txt', 'rb') as f:
reader = csv.reader(f)
scores = [int(row[-1]) for row in reader]
如果您希望它们以相反的顺序(从最高到最低)排序:
with open('highscores.txt', 'rb') as f:
reader = csv.reader(f)
scores = (int(row[-1]) for row in reader)
topscores = sorted(scores, reverse=True)
如果您只想要前 10 名:
with open('highscores.txt', 'rb') as f:
reader = csv.reader(f)
scores = (int(row[-1]) for row in reader)
topscores = sorted(scores, reverse=True)
top10 = topscores[:10]
heapq
通过使用该模块,您可以使最后一步更高效,但更复杂一些:
with open('highscores.txt', 'rb') as f:
reader = csv.reader(f)
scores = (int(row[-1]) for row in reader)
top10 = heapq.nlargest(10, scores)
从对另一个答案的评论中,您实际上想要获取每行中的所有四个值。因此,您需要读取整行,而不是只读取每一行的最后一列。此外,您可能希望将第一列转换为浮点数,将其余列转换为整数,这比仅将函数映射到每行中的所有列要复杂一些。同时,nlargest
orsorted
会按第一列比较,但你希望它按最后一列进行比较,这意味着你需要提供一个key 函数。虽然自己写一个并不难,但itemgetter
已经完全按照你的意愿做了。
with open('highscores.txt', 'rb') as f:
reader = csv.reader(f)
def convert_row(row):
return [float(row[0])] + [int(value) for value in row[1:]]
scores = (convert_row(row) for row in reader)
top10 = heapq.nlargest(10, scores, key=operator.itemgetter(-1))
for record in top10:
print('time: {} | moves: {} | penalties: {} | score: {}'.format(*record))
这段代码的唯一问题是列顺序的知识在你的代码中隐含地分散。如果您有一个字典列表,而不是列表列表,这将允许您按名称访问值。并DictReader
让您这样做:
with open('highscores.txt', 'rb') as f:
reader = csv.DictReader(f, fieldnames=('time', 'moves', 'penalties', 'score'))
def convert_row(row):
return {k: float(v) if k == 'time' else int(v) for k, v in row.items()}
scores = [convert_row(row) for row in reader]
top10 = heapq.nlargest(10, scores, key=operator.itemgetter('score'))
for record in top10:
print('time: {time} | moves: {moves} | penalties: {penalties} | score: {score}'
.format(**record))
函数中不再有 0、1:、-1 或隐式排序format
;现在一切都通过字段名称进行 - <code>time,除time
,score
等之外的任何内容。另一方面,代码更加冗长,有些人发现 dict 推导比列表推导/生成器表达式更难阅读,所以......这是否是一种改进是一个品味问题。