我正在为我的游戏创建一个高分表。它以下列格式将值附加到.txt文件:
5.234,0,0,5234
6.345,1,1,8345
1.649,0,1,2649
2.25,0,1,3250
...等等
我想读取前10个得分(得分是每行的第4个值)并将其输出到屏幕上。我尝试使用此处的信息,但无法理解。输出它们的最佳方法是什么?
我知道您可以使用拆分值
for line in f:
Array = line.split(',')
我很确定如果我将它们放在排序的2D数组或等效数组中,就可以管理输出
解决方案
使用该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)
如果您只想要前十名:
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或sorted将按第一列进行比较,但要与最后一列进行比较,这意味着您需要提供键功能。尽管自己写一点也不难,但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))
format函数中不再有0、1,-1或隐式排序;现在,所有内容都使用字段名称-time,但不包括time,score等等。另一方面,代码更加冗长,并且某些人发现dict理解比列表理解/生成器表达式更难读,所以……这是一个问题品尝这是否有所改善。