我正在为我的游戏创建一个高分榜。 它以下列格式将值附加到.txt文件:
5.234,0,0,5234
6.345,1,1,8345
1.649,0,1,2649
2.25,0,1,3250
...等
我想阅读前10个分数(分数是每行的第4个值) 并将它们输出到屏幕上。我尝试过使用here信息,但我无法理解它。输出它们的最佳方法是什么?
我知道您可以使用
分割值for line in f:
Array = line.split(',')
非常确定如果我将它们放在已排序的2D数组或等效的
中,我可以管理输出答案 0 :(得分:2)
使用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
或sorted
将按第一列进行比较,但您希望它按最后一列进行比较,这意味着您需要提供key function。虽然自己写一个并不困难,但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))
此代码的唯一问题是列顺序的知识在您的代码中隐式分散。如果您有一个dicts列表,而不是列表列表,这将允许您按名称访问值。 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
之外的任何内容等等。另一方面,代码更冗长,有些人更难找到字典理解阅读比列表理解/生成器表达式,所以...这是一个品味问题,这是否是一个改进。
答案 1 :(得分:1)
heapq.nlargest
完全是为此任务而设计的。让您的示例跟随代码输出前2个分数。根据您的需求进行修改
import heapq
lst = ['5.234,0,0,5234',
'6.345,1,1,8345',
'1.649,0,1,2649',
'2.25,0,1,3250']
scores = map(int, (l.split(',')[3] for l in lst))
print heapq.nlargest(2, scores)
答案 2 :(得分:1)
虽然不是严格要求,但我会使用csv
模块:
import csv
with open('scores.txt', 'rb') as csvfile:
values = [[float(row[0])] + map(int, row[1:]) for row in csv.reader(csvfile)]
top_ten = sorted(values, reverse=True, key=lambda v: v[3])[:10]
for row in top_ten:
print("time: {0:.3f} | moves: {1:,d} | "
"penalties: {2:,d} | score: {3:,d}".format(*row))
输出:
time: 6.345 | moves: 1 | penalties: 1 | score: 8,345
time: 5.234 | moves: 0 | penalties: 0 | score: 5,234
time: 2.250 | moves: 0 | penalties: 1 | score: 3,250
time: 1.649 | moves: 0 | penalties: 1 | score: 2,649
当然,您的样本数据实际上没有足够的总得分能够显示前十名。
答案 3 :(得分:0)
使用Python的csv库,这非常简单。
import csv
with open('scores.txt', 'r') as csvfile:
scorereader = csv.reader(csvfile, delimiter=',', quotechar='"')
for row in scorereader:
print ', '.join(row)
答案 4 :(得分:0)
with open('high_scores.txt') as f:
sorted([line.strip().split(',') for line in f], key=lambda x: int(x[3]), \
reverse=True)[:10]