0

我正在为我的游戏创建一个高分表。它将值附加到以下格式的 .txt 文件中:

5.234,0,0,5234
6.345,1,1,8345
1.649,0,1,2649
2.25,0,1,3250

...ETC

我想读取前 10 个分数(分数是每行的第 4 个值)并将它们输出到屏幕上。我已经尝试使用这里的信息,但我无法理解它。输出它们的最佳方法是什么?

我知道您可以使用拆分值

for line in f:
    Array = line.split(',')

如果我将它们放在排序的二维数组或等效数组中,我很确定我可以管理输出

4

5 回答 5

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)

从对另一个答案的评论中,您实际上想要获取每行中的所有四个值。因此,您需要读取整行,而不是只读取每一行的最后一列。此外,您可能希望将第一列转换为浮点数,将其余列转换为整数,这比仅将函数映射到每行中的所有列要复杂一些。同时,nlargestorsorted会按第一列比较,但你希望它按最后一列进行比较,这意味着你需要提供一个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 推导比列表推导/生成器表达式更难阅读,所以......这是否是一种改进是一个品味问题。

于 2013-10-24T20:25:28.647 回答
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)
于 2013-10-24T20:26:37.860 回答
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

当然,您的样本数据中实际上没有足够的总分来显示其中的前 10 名。

于 2013-10-24T20:27:59.497 回答
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)
于 2013-10-24T20:24:57.250 回答
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]
于 2013-10-24T20:26:52.573 回答