如何按值对字典进行排序?

3414

我有一个从数据库中读取的键值对字典:一个字符串字段和一个数字字段。字符串字段是唯一的,所以它是字典的键。

我可以按照键排序,但是如何基于值排序呢?

注意:我已经在Stack Overflow上阅读了这里的问题:How do I sort a list of dictionaries by a value of the dictionary?,并且可能可以更改我的代码以使用字典列表,但由于我实际上不需要字典列表,我想知道是否有更简单的解决方案来升序或降序排序。


9
字典数据结构没有固有的顺序。虽然可以遍历它,但不能保证遍历的顺序是特定的。这是设计上的考虑,因此最好使用另一种数据结构来表示。 - Daishiman
135
"sorted()" 函数可以用于字典(并返回已排序的键列表),因此我认为他知道这一点。如果不了解其程序,就告诉别人他们使用了错误的数据结构是荒谬的。如果你需要90%的时间快速查找,则可能需要使用字典。 - bobpaul
这里清晰简洁地介绍了排序字典的三种输出方式(键、值、两者):https://dev59.com/nGQn5IYBdhLWcg3wg3aR - JStrahl
2
@Daishiman 基类可能没有排序,但是OrderedDict当然是有序的。 - Taylor D. Edmiston
1
在Python 3.6+中,字典保留插入顺序。当然,这并不意味着可以按值对它们进行排序,但另一方面,不能再说“字典数据结构没有固有的顺序”了。 - Konrad Kocik
34个回答

17

当然,记住,你需要使用OrderedDict,因为普通的Python字典不能保持原始顺序。

from collections import OrderedDict
a = OrderedDict(sorted(originalDict.items(), key=lambda x: x[1]))
如果您没有 Python 2.7 或更高版本,则最好的方法是迭代生成器函数中的值。(这里有一个用于 2.4 和 2.6 的 OrderedDict,链接在这里,但是 a) 我不知道它的表现如何,以及 b) 您需要下载并安装它。如果您没有管理员权限,则恐怕这个选项不可行。)
def gen(originalDict):
    for x, y in sorted(zip(originalDict.keys(), originalDict.values()), key=lambda z: z[1]):
        yield (x, y)
    #Yields as a tuple with (key, value). You can iterate with conditional clauses to get what you want. 

for bleh, meh in gen(myDict):
    if bleh == "foo":
        print(myDict[bleh])
您也可以打印出每个值。
for bleh, meh in gen(myDict):
    print(bleh, meh)
请记得在使用Python 3.0或更高版本之外的版本时,删除print后面的括号。

1
常规的Python字典不会保留原始顺序,但是从Python 3.7开始,它们可以保留原始顺序。 - gerrit


15
from django.utils.datastructures import SortedDict

def sortedDictByKey(self,data):
    """Sorted dictionary order by key"""
    sortedDict = SortedDict()
    if data:
        if isinstance(data, dict):
            sortedKey = sorted(data.keys())
            for k in sortedKey:
                sortedDict[k] = data[k]
    return sortedDict

2
问题是:按值排序,而不是按键排序...我喜欢看到一个函数。您可以导入collections并当然使用sorted(data.values())。 - Remi

14

正如Dilettant所指出的,Python 3.6现在会保留顺序!我想分享一个我编写的函数,可以简化对可迭代对象(元组、列表、字典)进行排序的过程。在后一种情况下,您可以按键或值进行排序,并且它可以考虑数值比较。仅适用于 >= 3.6版本!

当您尝试使用sorted()对包含字符串和整数等不同类型的元素的可迭代对象进行排序时,sorted()会失败。当然,您可以通过str()强制使用字符串比较。但是,在某些情况下,您希望进行实际的数字比较,其中12小于20(这在字符串比较中不是这样的)。因此,我想到了以下解决方案。当您需要明确的数字比较时,可以使用标志num_as_num,它将尝试将所有值转换为浮点数来进行显式的数字排序。如果成功,则进行数字排序,否则将回归到字符串比较。

欢迎提出改进意见。

def sort_iterable(iterable, sort_on=None, reverse=False, num_as_num=False):
    def _sort(i):
      # sort by 0 = keys, 1 values, None for lists and tuples
      try:
        if num_as_num:
          if i is None:
            _sorted = sorted(iterable, key=lambda v: float(v), reverse=reverse)
          else:
            _sorted = dict(sorted(iterable.items(), key=lambda v: float(v[i]), reverse=reverse))
        else:
          raise TypeError
      except (TypeError, ValueError):
        if i is None:
          _sorted = sorted(iterable, key=lambda v: str(v), reverse=reverse)
        else:
          _sorted = dict(sorted(iterable.items(), key=lambda v: str(v[i]), reverse=reverse))
      
      return _sorted
      
    if isinstance(iterable, list):
      sorted_list = _sort(None)
      return sorted_list
    elif isinstance(iterable, tuple):
      sorted_list = tuple(_sort(None))
      return sorted_list
    elif isinstance(iterable, dict):
      if sort_on == 'keys':
        sorted_dict = _sort(0)
        return sorted_dict
      elif sort_on == 'values':
        sorted_dict = _sort(1)
        return sorted_dict
      elif sort_on is not None:
        raise ValueError(f"Unexpected value {sort_on} for sort_on. When sorting a dict, use key or values")
    else:
      raise TypeError(f"Unexpected type {type(iterable)} for iterable. Expected a list, tuple, or dict")

14

我刚从Python for Everybody学到了一项相关技能。

你可以使用一个临时列表来帮助你对字典进行排序:

# Assume dictionary to be:
d = {'apple': 500.1, 'banana': 1500.2, 'orange': 1.0, 'pineapple': 789.0}

# Create a temporary list
tmp = []

# Iterate through the dictionary and append each tuple into the temporary list
for key, value in d.items():
    tmptuple = (value, key)
    tmp.append(tmptuple)

# Sort the list in ascending order
tmp = sorted(tmp)

print (tmp)

如果您想要按照降序排列列表,只需将原排序行更改为:

tmp = sorted(tmp, reverse=True)

使用列表推导式,这个一行代码的方式如下:

# Assuming the dictionary looks like
d = {'apple': 500.1, 'banana': 1500.2, 'orange': 1.0, 'pineapple': 789.0}
# One-liner for sorting in ascending order
print (sorted([(v, k) for k, v in d.items()]))
# One-liner for sorting in descending order
print (sorted([(v, k) for k, v in d.items()], reverse=True))

输出示例:

# Ascending order
[(1.0, 'orange'), (500.1, 'apple'), (789.0, 'pineapple'), (1500.2, 'banana')]
# Descending order
[(1500.2, 'banana'), (789.0, 'pineapple'), (500.1, 'apple'), (1.0, 'orange')]

如果您想以初始格式打印它,应该执行以下操作:print([(k,v) for v,k in sorted([(v,k) for k,v in d.items()])])。输出为:[('orange', 1.0), ('apple', 500.1), ('pineapple', 789.0), ('banana', 1500.2)]。使用[(k,v) for v,k in sorted([(v,k) for k,v in d.items()], reverse = True)],输出为:[('banana', 1500.2), ('pineapple', 789.0), ('apple', 500.1), ('orange', 1.0)]。 - Hermes Morales

10

使用来自dictsValueSortedDict

from dicts.sorteddict import ValueSortedDict
d = {1: 2, 3: 4, 4:3, 2:1, 0:0}
sorted_dict = ValueSortedDict(d)
print sorted_dict.items() 

[(0, 0), (2, 1), (1, 2), (4, 3), (3, 4)]

10

遍历字典并按其值降序排序:

$ python --version
Python 3.2.2

$ cat sort_dict_by_val_desc.py 
dictionary = dict(siis = 1, sana = 2, joka = 3, tuli = 4, aina = 5)
for word in sorted(dictionary, key=dictionary.get, reverse=True):
  print(word, dictionary[word])

$ python sort_dict_by_val_desc.py 
aina 5
tuli 4
joka 3
sana 2
siis 1

9
如果您的值是整数,并且您使用的是Python 2.7或更新版本,则可以使用collections.Counter代替dictmost_common方法将按值排序给出所有项。

8

这在3.1.x版本中有效:

import operator
slovar_sorted=sorted(slovar.items(), key=operator.itemgetter(1), reverse=True)
print(slovar_sorted)

8

为了完整起见,我将发布一种使用heapq的解决方案。请注意,此方法适用于数值和非数值。

>>> x = {1: 2, 3: 4, 4:3, 2:1, 0:0}
>>> x_items = x.items()
>>> heapq.heapify(x_items)
>>> #To sort in reverse order
>>> heapq.nlargest(len(x_items),x_items, operator.itemgetter(1))
[(3, 4), (4, 3), (1, 2), (2, 1), (0, 0)]
>>> #To sort in ascending order
>>> heapq.nsmallest(len(x_items),x_items, operator.itemgetter(1))
[(0, 0), (2, 1), (1, 2), (4, 3), (3, 4)]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接