如何将字典排序为仅从最高值输出?

时间:2015-01-27 21:43:55

标签: python sorting dictionary

txt会包含以下内容:

Matt Scored: 10
Jimmy Scored: 3
James Scored: 9
Jimmy Scored: 8
....

到目前为止我的代码:

   from collections import OrderedDict
#opens the class file in order to create a dictionary
dictionary = {}
#splits the data so the name is the key while the score is the value
f = open('ClassA.txt', 'r')
d = {}
for line in f:
    firstpart, secondpart = line.strip().split(':')
    dictionary[firstpart.strip()] = secondpart.strip()
    columns = line.split(": ")
    letters = columns[0]
    numbers = columns[1].strip()
    if d.get(letters):
        d[letters].append(numbers)
    else:
        d[letters] = list(numbers)
#sorts the dictionary so it has a alphabetical order
sorted_dict = OrderedDict(
sorted((key, list(sorted(vals, reverse=True))) 
       for key, vals in d.items()))
print (sorted_dict)

此代码已生成按字母顺序排序的名称输出,其分数从最高到最低打印。但是现在我需要能够输出以最高得分为第一,最低得分为最后得分的名称。我尝试使用max函数,但它只输出名称而不是分数本身,我也希望输出的分数最高,而不是之前的分数,就像我当前的代码一样。

4 个答案:

答案 0 :(得分:1)

在这种情况下,我认为你不需要字典。只需将分数作为元组列表。

即。按名称排序:

>>> sorted([('c', 10), ('b', 16), ('a', 5)], 
           key = lambda row: row[0])
[('a', 5), ('b', 16), ('c', 10)]

或者得分:

>>> sorted([('c', 10), ('b', 16), ('a', 5)], 
           key = lambda row: row[1])
[('a', 5), ('c', 10), ('b', 16)]

答案 1 :(得分:0)

您可以使用itertools.groupby自行分隔每个密钥。那个很长的dict comp很难看,但它主要是通过对输入进行排序,将它按冒号前的部分分组,然后取出最大的结果并用组名保存它。

import itertools, operator

text = """Matt Scored: 10
Jimmy Scored: 3
James Scored: 9
Jimmy Scored: 8"""

result_dict = {group:max(map(lambda s: int(s.split(":")[1]), vals)) for
               group,vals in itertools.groupby(sorted(text.splitlines()),
                                               lambda s: s.split(":")[0])}

sorted_dict = sorted(result_dict.items(), key=operator.itemgetter(1), reverse=True)
# result:
[('Matt Scored', 10), ('James Scored', 9), ('Jimmy Scored', 8)]

展开dict comp会产生类似的结果:

sorted_txt = sorted(text.splitlines())
groups = itertools.groupby(sorted_txt, lambda s: s.split(":")[0])
result_dict = {}
for group, values in groups:
    # group is the first half of the line
    result_dict[group] = -1
    # some arbitrary small number
    for value in values:
        #value is the whole line, so....
        value = value.split(":")[1]
        value = int(value)
        result_dict[group] = max(result_dict[group], value)

答案 2 :(得分:0)

我会从一开始就使用 bisect.insort ,每当你插入一个新的分数时都会有一个排序列表,那么只需要反转或slicing the list来获得期望的输出:

from bisect import insort
from StringIO import StringIO

d = {}
f = '''Matt Scored: 10
Jimmy Scored: 3
James Scored: 9
Jimmy Scored: 8'''

for line in StringIO(f):
    line = line.strip().split(' Scored: ')
    name, score = line[0], int(line[1])
    if d.get(name):
        # whenever new score is inserted, it's sorted from low > high
        insort(d[name], score)
    else:
        d[name] = [score]

d

{'James': [9], 'Jimmy': [3, 8], 'Matt': [10]}

然后获得所需的输出:

for k in sorted(d.keys()):
    # score from largest to smallest, sorted by names
    print 'sorted name, high>low score  ', k, d[k][::-1]
    # highest score, sorted by name
    print 'sorted name, highest score ', k, d[k][-1]

结果:

sorted name, high>low score   James [9]
sorted name, highest score  James 9
sorted name, high>low score   Jimmy [8, 3]
sorted name, highest score  Jimmy 8
sorted name, high>low score   Matt [10]
sorted name, highest score  Matt 10

作为旁注list[::-1] ==反向列表,list[-1] ==最后一个元素

答案 3 :(得分:0)

使用defaultdict

可以简化您的代码
from collections import defaultdict
d = defaultdict(list)

接下来,在处理文件时使用open上下文管理器是一种很好的做法。

with open('ClassA.txt') as f:

最后,当循环遍历f的行时,您应该使用单个字典,而不是两个字典。要更轻松地按分数排序,您需要将分数存储为int

    for line in f:
        name, score = line.split(':')
        d[name.strip()].append(int(score.strip()))

此方法的一个副作用是,在创建新列表时,具有多个数字的分数(例如Jimmy Scored: 10)将保持其值(10)。在原始版本中,list('10')会生成list['1', '0']

您可以使用sorted的{​​{1}}参数按key中的值而不是其键进行排序。

d

把它们放在一起我们得到了

sorted(d, key=lambda x: max(d[x]))