假设我有一个(文本)文件,其结构如下(名称,分数):
a 0
a 1
b 0
c 0
d 3
b 2
等等。我的目标是将每个名字的分数相加,并从最高分到最低分排序。所以在这种情况下,我想要以下输出:
d 3
b 2
a 1
c 0
事先我不知道文件中会有什么名字。
我想知道是否有一种有效的方法可以做到这一点。我的文本文件最多可包含50,000个条目。
我能想到的唯一方法就是从第1行开始,记住该名称,然后查看整个文件以查找该名称和总和。这看起来非常低效,所以我想知道是否有更好的方法来做到这一点。
答案 0 :(得分:12)
将所有数据读入字典:
from collections import defaultdict
from operator import itemgetter
scores = defaultdict(int)
with open('my_file.txt') as fobj:
for line in fobj:
name, score = line.split()
scores[name] += int(score)
和排序:
for name, score in sorted(scores.items(), key=itemgetter(1), reverse=True):
print(name, score)
打印:
d 3
b 2
a 1
c 0
为了检查这个答案与@SvenMarnach的答案的表现,我将两种方法都放入一个函数中。这里fobj
是一个打开阅读的文件。
我使用io.StringIO
因此有希望无法测量IO延迟:
from collections import Counter
def counter(fobj):
scores = Counter()
fobj.seek(0)
for line in fobj:
key, score = line.split()
scores.update({key: int(score)})
return scores.most_common()
from collections import defaultdict
from operator import itemgetter
def default(fobj):
scores = defaultdict(int)
fobj.seek(0)
for line in fobj:
name, score = line.split()
scores[name] += int(score)
return sorted(scores.items(), key=itemgetter(1), reverse=True)
collections.Counter
的结果:
%timeit counter(fobj)
10000 loops, best of 3: 59.1 µs per loop
collections.defaultdict
的结果:
%timeit default(fobj)
10000 loops, best of 3: 15.8 µs per loop
看起来defaultdict
的速度提高了四倍。我不会猜到这一点。但是在性能方面,您需要来衡量。
答案 1 :(得分:7)
这是collections.Counter
的一个很好的用例:
from collections import Counter
scores = Counter()
with open('my_file') as f:
for line in f:
key, score = line.split()
scores.update({key: int(score)})
for key, score in scores.most_common():
print(key, score)
答案 2 :(得分:0)
熊猫可以相当容易地做到这一点:
import pandas as pd
data = pd.read_csv('filename.txt', names=['Name','Score'])
sorted = data.groupby('Name').sum().sort_values('Score', ascending=False)
print sorted