【问题标题】:How to sort a dictionary to output from only highest value?如何对字典进行排序以仅从最高值输出?
【发布时间】:2015-01-27 21:43:54
【问题描述】:

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 函数,但是它只输出名称而不是分数本身,而且我希望输出只有最高分,而不是像我当前代码那样的以前的分数。

【问题讨论】:

标签: python sorting dictionary


【解决方案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)]

【讨论】:

  • 在这些情况下你应该使用operator.itemgetter,而不是编写你自己的匿名函数
【解决方案2】:

您可以使用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)

【讨论】:

    【解决方案3】:

    每当您插入新分数时,我会从一开始就使用 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] == 最后一个元素

    【讨论】:

      【解决方案4】:

      您的代码可以使用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']

      您可以使用sortedkey 参数按d 中的值而不是其键进行排序。

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

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

      from collections import defaultdict
      d = defaultdict(list)
      with open('ClassA.txt') as f:
          for line in f:
              name, score = line.split(':')
              d[name.strip()].append(int(score.strip()))
      
      # Original
      print(sorted(d.items()))
      
      # By score ascending
      print(sorted(d.items(), key=lambda x: max(x[1])))
      
      # By score descending
      print(sorted(d.items(), key=lambda x: max(x[1]), reverse=True))
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-12-21
        • 1970-01-01
        • 2010-10-11
        相关资源
        最近更新 更多