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

我有一个从数据库中的两个字段读取值的字典:一个字符串字段和一个数字字段。string字段是惟一的,所以这是字典的键。

我可以按键排序,但是如何根据值排序呢?

注意:我在这里读过堆栈溢出问题,我如何根据字典的值对字典列表排序?也许还可以将我的代码更改为字典列表,但由于我实际上并不需要字典列表,所以我想知道是否有一种更简单的解决方案可以按升序或降序排序。


不可能对字典进行排序,只能得到已排序的字典的表示形式。字典本身是无序的,但是其他类型,如列表和元组,则不是。因此,您需要一个有序的数据类型来表示已排序的值,这将是一个列表—可能是一个元组列表。

例如,

1
2
3
import operator
x = {1: 2, 3: 4, 4: 3, 2: 1, 0: 0}
sorted_x = sorted(x.items(), key=operator.itemgetter(1))

sorted_x将是按每个元组中的第二个元素排序的元组列表。dict(sorted_x) == x

对于那些希望按键排序而不是按值排序的用户:

1
2
3
import operator
x = {1: 2, 3: 4, 4: 3, 2: 1, 0: 0}
sorted_x = sorted(x.items(), key=operator.itemgetter(0))

在Python3中,因为解压是不允许的,所以我们可以使用[1]

1
2
x = {1: 2, 3: 4, 4: 3, 2: 1, 0: 0}
sorted_x = sorted(x.items(), key=lambda kv: kv[1])

如果您希望输出为dict,可以使用collections.OrderedDict:

1
2
3
import collections

sorted_dict = OrderedDict(sorted_x)


As simple As: sorted(dict1, key=dict1.get)

实际上,"按字典值排序"是可能的。最近,我不得不在一个代码高尔夫(堆栈溢出问题代码高尔夫:单词频率表)中这样做。简而言之,问题是这样的:给定一个文本,计算每个单词出现的频率,并显示一个按频率递减排序的最热门单词列表。

如果构造一个字典,其中单词作为键,每个单词出现的次数作为值,在这里简化为:

1
2
3
4
from collections import defaultdict
d = defaultdict(int)
for w in text.split():
  d[w] += 1

然后,您可以得到一个单词列表,按照使用sorted(d, key=d.get)的频率排序——sort遍历字典键,使用单词出现的次数作为排序键。

1
2
for w in sorted(d, key=d.get, reverse=True):
  print w, d[w]

我写这篇详细的解释是为了说明人们通常所说的"我可以轻松地按键对字典排序,但如何按值排序"是什么意思——我认为OP正试图解决这个问题。解决方案是基于这些值,对键列表进行排序,如上所示。


您可以使用:

sorted(d.items(), key=lambda x: x[1])

这将根据字典中每个条目的值从最小到最大对字典进行排序。


Dicts不能排序,但您可以从它们构建一个排序列表。

dict值的排序列表:

1
sorted(d.values())

按值排序的(键、值)对列表:

1
2
from operator import itemgetter
sorted(d.items(), key=itemgetter(1))


在最近的Python 2.7中,我们有了新的OrderedDict类型,它记住了添加项的顺序。

1
2
3
4
5
6
7
8
9
10
11
12
>>> d = {"third": 3,"first": 1,"fourth": 4,"second": 2}

>>> for k, v in d.items():
...     print"%s: %s" % (k, v)
...
second: 2
fourth: 4
third: 3
first: 1

>>> d
{'second': 2, 'fourth': 4, 'third': 3, 'first': 1}

要从原来的字典中创建一个新的有序字典,按值排序:

1
2
>>> from collections import OrderedDict
>>> d_sorted_by_value = OrderedDict(sorted(d.items(), key=lambda x: x[1]))

OrderedDict的行为与普通dict类似:

1
2
3
4
5
6
7
8
9
10
>>> for k, v in d_sorted_by_value.items():
...     print"%s: %s" % (k, v)
...
first: 1
second: 2
third: 3
fourth: 4

>>> d_sorted_by_value
OrderedDict([('first': 1), ('second': 2), ('third': 3), ('fourth': 4)])


更新:2015年12月5日使用Python 3.5

虽然我发现公认的答案是有用的,但我也很惊讶,它没有被更新为引用来自标准库集合模块的OrderedDict作为一个可行的、现代的替代方法—设计用于解决这类问题。

1
2
3
4
5
6
from operator import itemgetter
from collections import OrderedDict

x = {1: 2, 3: 4, 4: 3, 2: 1, 0: 0}
sorted_x = OrderedDict(sorted(x.items(), key=itemgetter(1)))
# OrderedDict([(0, 0), (2, 1), (1, 2), (4, 3), (3, 4)])

官方的OrderedDict文档也提供了一个非常类似的例子,但是使用lambda来执行排序函数:

1
2
3
4
5
6
# regular unsorted dictionary
d = {'banana': 3, 'apple':4, 'pear': 1, 'orange': 2}

# dictionary sorted by value
OrderedDict(sorted(d.items(), key=lambda t: t[1]))
# OrderedDict([('pear', 1), ('orange', 2), ('banana', 3), ('apple', 4)])

使用namedtuple通常非常方便。例如,你有一个字典,"name"作为键,"score"作为值,你想对"score"排序:

1
2
3
import collections
Player = collections.namedtuple('Player', 'score name')
d = {'John':5, 'Alex':10, 'Richard': 7}

以最低分排序:

1
worst = sorted(Player(v,k) for (k,v) in d.items())

以最高分排名第一:

1
best = sorted([Player(v,k) for (k,v) in d.items()], reverse=True)

现在你可以得到的名字和分数,让我们说,第二好的球员(index=1)非常勾股定理像这样:

1
2
3
4
5
player = best[1]
player.name
    'Richard'
player.score
    7


和汉克·盖伊的回答差不多:

1
sorted([(value,key) for (key,value) in mydict.items()])

或者像John Fouhy建议的那样稍微优化一下:

1
sorted((value,key) for (key,value) in mydict.items())


从Python 3.6开始,内置的dict将被命令

好消息是,OP最初的映射对用惟一字符串id作为键、数字值作为值从数据库检索到内置Python v3.6+ dict的用例现在应该尊重插入顺序。

如果从数据库查询中得到两个列表表达式,如:

1
SELECT a_key, a_value FROM a_table ORDER BY a_value;

将存储在两个Python元组k_seq和v_seq中(按数值索引对齐,当然长度相同),则:

1
2
3
k_seq = ('foo', 'bar', 'baz')
v_seq = (0, 1, 42)
ordered_map = dict(zip(k_seq, v_seq))

允许稍后输出如下:

1
2
for k, v in ordered_map.items():
    print(k, v)

在这种情况下(对于新的Python 3.6+内置dict!)

1
2
3
foo 0
bar 1
baz 42

在相同的顺序下,每个v的值。

在Python 3.5安装到我的机器,它目前产生:

1
2
3
bar 1
foo 0
baz 42

细节:

2012年Raymond Hettinger (cf. mail on Python -dev with subject"More compact dictionary with faster iteration")提出,现在(2016年)Victor Stinner在给Python -dev的邮件中宣布"Python 3.6 dict变得紧凑,并获得了一个私有版本;而关键字变得有序"由于修复/实现问题27350"紧凑和有序的dict"在Python 3.6中,我们现在将能够使用内置的dict来维护插入顺序!!

希望这将导致作为第一步的瘦层OrderedDict实现。正如@JimFasarakis-Hilliard所指出的,有些人在将来还会看到OrderedDict类型的用例。我认为整个Python社区都会仔细检查,看看这能否经受住时间的考验,以及接下来的步骤是什么。

是时候重新思考我们的编码习惯了,不要错过以下稳定的顺序所带来的可能性:

关键字参数,(中间)dict存储

第一是因为它在某些情况下简化了函数和方法实现中的分派。

第二个原因是它鼓励在处理管道中更容易地使用dict作为中间存储。

Raymond Hettinger在他的旧金山Python Meetup小组报告(2016年12月-08日)中提供了解释"Python 3.6字典背后的技术"的文档。

而且可能相当多的堆栈溢出高装饰的问答页面将接收这些信息的变体,许多高质量的答案也需要每个版本的更新。

出门概不退换(但也请参见更新2017-12-15):

正如@ajcr正确地指出的:"这个新实现的订单保留方面被认为是一个实现细节,不应该依赖于它。"(摘自whatsnew36)不是nit采摘,但引文被削减了一点悲观;-)。它继续作为"(这在未来可能会发生变化,但是在更改语言规范以强制要求所有当前和未来Python实现保持顺序语义之前,希望在几个版本中使用这种新的dict实现;这也有助于保持向后兼容的语言的旧版本,其中随机迭代顺序仍然有效,如Python 3.5)。

因此,在一些人类语言(如德语)中,使用塑造了语言,而遗嘱现在已经被宣布……在whatsnew36。

更新2017-12-15:

在给python-dev列表的邮件中,Guido van Rossum声明:

Make it so."Dict keeps insertion order" is the ruling. Thanks!

因此,CPython 3.6版本中dict插入顺序的副作用现在已经成为语言规范的一部分(而不仅仅是实现细节)。正如Raymond Hettinger在讨论中所提醒的,该邮件线程还为collections.OrderedDict提出了一些不同的设计目标。


鉴于字典

1
e = {1:39, 4:34, 7:110, 2:87}

排序

1
sred = sorted(e.items(), key=lambda value: value[1])

结果

1
[(4, 34), (1, 39), (2, 87), (7, 110)]

您可以使用lambda函数按值排序,并将它们存储在一个变量中进行处理,在本例中是使用原始字典sred。

希望会有帮助!


我有同样的问题,我是这样解决的:

1
WantedOutput = sorted(MyDict, key=lambda x : MyDict[x])

(回答"It is not possible to sort a dict"的人没有阅读问题!事实上,"我可以对键进行排序,但是如何根据值进行排序呢?"这显然意味着他想要根据键值排序的键列表。

请注意,顺序没有很好地定义(具有相同值的键在输出列表中是任意顺序的)。


在Python 2.7中,只需:

1
2
3
4
5
6
7
8
9
10
11
from collections import OrderedDict
# regular unsorted dictionary
d = {'banana': 3, 'apple':4, 'pear': 1, 'orange': 2}

# dictionary sorted by key
OrderedDict(sorted(d.items(), key=lambda t: t[0]))
OrderedDict([('apple', 4), ('banana', 3), ('orange', 2), ('pear', 1)])

# dictionary sorted by value
OrderedDict(sorted(d.items(), key=lambda t: t[1]))
OrderedDict([('pear', 1), ('orange', 2), ('banana', 3), ('apple', 4)])

复制粘贴:http://docs.python.org/dev/library/collections.html#ordereddict-examples-and-recipes

享受;-)


从技术上讲,字典不是序列,因此不能排序。你可以这样做

1
sorted(a_dictionary.values())

假设性能不是什么大事。


代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import operator
origin_list = [
    {"name":"foo","rank": 0,"rofl": 20000},
    {"name":"Silly","rank": 15,"rofl": 1000},
    {"name":"Baa","rank": 300,"rofl": 20},
    {"name":"Zoo","rank": 10,"rofl": 200},
    {"name":"Penguin","rank": -1,"rofl": 10000}
]
print">> Original >>"
for foo in origin_list:
    print foo

print"
>> Rofl sort >>"

for foo in sorted(origin_list, key=operator.itemgetter("rofl")):
    print foo

print"
>> Rank sort >>"

for foo in sorted(origin_list, key=operator.itemgetter("rank")):
    print foo

结果如下:

原始

1
2
3
4
5
{'name': 'foo', 'rank': 0, 'rofl': 20000}
{'name': 'Silly', 'rank': 15, 'rofl': 1000}
{'name': 'Baa', 'rank': 300, 'rofl': 20}
{'name': 'Zoo', 'rank': 10, 'rofl': 200}
{'name': 'Penguin', 'rank': -1, 'rofl': 10000}

Rofl

1
2
3
4
5
{'name': 'Baa', 'rank': 300, 'rofl': 20}
{'name': 'Zoo', 'rank': 10, 'rofl': 200}
{'name': 'Silly', 'rank': 15, 'rofl': 1000}
{'name': 'Penguin', 'rank': -1, 'rofl': 10000}
{'name': 'foo', 'rank': 0, 'rofl': 20000}

排名

1
2
3
4
5
{'name': 'Penguin', 'rank': -1, 'rofl': 10000}
{'name': 'foo', 'rank': 0, 'rofl': 20000}
{'name': 'Zoo', 'rank': 10, 'rofl': 200}
{'name': 'Silly', 'rank': 15, 'rofl': 1000}
{'name': 'Baa', 'rank': 300, 'rofl': 20}


如果值是数值,还可以使用来自集合的计数器

1
2
3
4
5
6
7
8
from collections import Counter

x={'hello':1,'python':5, 'world':3}
c=Counter(x)
print c.most_common()


>> [('python', 5), ('world', 3), ('hello', 1)]


试试下面的方法。让我们用以下数据定义一个名为mydict的字典:

1
2
3
4
mydict = {'carl':40,
          'alan':2,
          'bob':1,
          'danny':3}

如果想按键对字典排序,可以这样做:

1
2
for key in sorted(mydict.iterkeys()):
    print"%s: %s" % (key, mydict[key])

这应该返回以下输出:

1
2
3
4
alan: 2
bob: 1
carl: 40
danny: 3

另一方面,如果想按值对字典排序(就像问题中问的那样),可以这样做:

1
2
for key, value in sorted(mydict.iteritems(), key=lambda (k,v): (v,k)):
    print"%s: %s" % (key, value)

这个命令的结果(按值排序字典)应该返回以下内容:

1
2
3
4
bob: 1
alan: 2
danny: 3
carl: 40


你可以用收藏品。注意,这对数值和非数值都适用。

1
2
3
4
5
6
7
8
9
10
11
12
>>> x = {1: 2, 3: 4, 4:3, 2:1, 0:0}
>>> from collections import Counter
>>> #To sort in reverse order
>>> Counter(x).most_common()
[(3, 4), (4, 3), (1, 2), (2, 1), (0, 0)]
>>> #To sort in ascending order
>>> Counter(x).most_common()[::-1]
[(0, 0), (2, 1), (1, 2), (4, 3), (3, 4)]
>>> #To get a dictionary sorted by values
>>> from collections import OrderedDict
>>> OrderedDict(Counter(x).most_common()[::-1])
OrderedDict([(0, 0), (2, 1), (1, 2), (4, 3), (3, 4)])


您还可以创建一个"反向索引"

1
2
3
4
from collections import defaultdict
inverse= defaultdict( list )
for k, v in originalDict.items():
    inverse[v].append( k )

现在你的逆矩阵有这些值;每个值都有一个适用键的列表。

1
2
for k in sorted(inverse):
    print k, inverse[k]

返回字典中的键值对列表,按值从高到低排序:

1
sorted(d.items(), key=lambda x: x[1], reverse=True)

对于按键排序的字典,请使用以下命令:

1
sorted(d.items(), reverse=True)

返回的是一个元组列表,因为字典本身无法排序。

这可以打印或发送到进一步的计算。


可以使用skip dict,这是一个按值永久排序的字典。

1
2
3
>>> data = {1: 2, 3: 4, 4: 3, 2: 1, 0: 0}
>>> SkipDict(data)
{0: 0.0, 2: 1.0, 1: 2.0, 4: 3.0, 3: 4.0}

如果您使用keys()values()items(),那么您将按值的顺序进行迭代。

它是使用跳过列表数据结构实现的。


1
2
3
4
5
6
7
8
9
10
11
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


从Python 3.6开始,dict对象现在按插入顺序排序。它正式出现在Python 3.7规范中。

1
2
3
>>> words = {"python": 2,"blah": 4,"alice": 3}
>>> dict(sorted(words.items(), key=lambda x: x[1]))
{'python': 2, 'alice': 3, 'blah': 4}

在此之前,必须使用OrderedDict

Python 3.7文档中说:

Changed in version 3.7: Dictionary order is guaranteed to be insertion
order. This behavior was implementation detail of CPython from 3.6.


您还可以使用可以传递给key的自定义函数。

1
2
3
4
def dict_val(x):
    return x[1]
x = {1: 2, 3: 4, 4: 3, 2: 1, 0: 0}
sorted_x = sorted(x.items(), key=dict_val)

另一种方法是使用labmda函数

1
2
x = {1: 2, 3: 4, 4: 3, 2: 1, 0: 0}
sorted_x = sorted(x.items(), key=lambda t: t[1])

正如Dilettant所指出的,Python 3.6现在将保持秩序!我想我应该分享一个我写的函数,它简化了可迭代(元组、列表、dict)的排序。在后一种情况下,可以根据键或值进行排序,并且可以考虑数字比较。仅适用于>= 3.6!

当您尝试在包含字符串和int的迭代器上使用ordered()时,sort()将失败。当然,您可以使用str()强制字符串比较。但是,在某些情况下,您希望在12小于20的情况下进行实际的数值比较(字符串比较中不是这种情况)。所以我想到了以下几点。当您需要显式的数值比较时,您可以使用num_as_num标志,它将尝试通过将所有值转换为浮点数来进行显式的数值排序。如果成功,它将执行数字排序,否则将使用字符串比较。

欢迎对改进或推送请求提出意见。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
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")


下面是一个在d.values()d.keys()上使用zip的解决方案。下面的几行链接(在字典视图对象上)是:

This allows the creation of (value, key) pairs using zip(): pairs = zip(d.values(), d.keys()).

我们可以这样做:

1
2
3
4
5
6
d = {'key1': 874.7, 'key2': 5, 'key3': 8.1}

d_sorted = sorted(zip(d.values(), d.keys()))

print d_sorted
# prints: [(5, 'key2'), (8.1, 'key3'), (874.7, 'key1')]

使用dicts中的ValueSortedDict:

1
2
3
4
5
6
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)]

遍历dict并按其值降序排序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ 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

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


我想到了这个,

1
2
3
import operator    
x = {1: 2, 3: 4, 4:3, 2:1, 0:0}
sorted_x = {k[0]:k[1] for k in sorted(x.items(), key=operator.itemgetter(1))}

Python 3。x: x.items()替换iteritems()

1
2
>>> sorted_x
{0: 0, 1: 2, 2: 1, 3: 4, 4: 3}

或者用collections.OrderedDict试试!

1
2
3
4
x = {1: 2, 3: 4, 4:3, 2:1, 0:0}
from collections import OrderedDict

od1 = OrderedDict(sorted(x.items(), key=lambda t: t[1]))


可以使用Python的排序函数

sorted(iterable[, cmp[, key[, reverse]]])

因此,你可以用:

sorted(dictionary.items(),key = lambda x :x[1])

有关已排序函数的更多信息,请访问此链接:https://docs.python.org/2/library/functions.html#已排序函数


当然,请记住,您需要使用OrderedDict,因为常规Python字典不会保持原始顺序。

1
2
from collections import OrderedDict
a = OrderedDict(sorted(originalDict.items(), key = lambda x: x[1]))

如果没有Python 2.7或更高版本,最好的方法是遍历生成器函数中的值。(这里有一个OrderedDict用于2.4和2.6,但是

1
a) I don't know about how well it works

1
b) You have to download and install it of course. If you do not have administrative access, then I'm afraid the option's out.)
1
2
3
4
5
6
7
8
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])

您还可以打印出每个值

1
2
for bleh, meh in gen(myDict):
    print(bleh,meh)

如果不使用Python 3.0或以上版本,请记住打印后删除括号


这在3.1.x中是可行的:

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

只是从Python中为大家学习了相关的技能。

你可以使用一个临时列表来帮助你整理字典:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#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)

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

1
tmp = sorted(tmp, reverse=True)

使用列表理解,一行代码是:

1
2
3
4
5
6
#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))

样例输出:

1
2
3
4
#Asending 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')]

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

1
2
3
4
5
6
7
8
9
>>> 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)]


Thomas Cokelaer用一种非常优雅的方式解释了这一点。我想简要地提一下他的文章。

让我们考虑一下下面的词典。

1
d = {"Pierre": 42,"Anne": 33,"Zoe": 24}

为了根据这些值进行排序,本文介绍了以下几种方法。

sorted函数和operator模块

1
2
import operator
sorted_d = sorted(d.items(), key=operator.itemgetter(1))

sorted函数和lambda函数

1
sorted_d = sorted(d.items(), key=lambda x: x[1])

函数并返回一个有序字典

在前面的方法中,返回的对象是元组列表。所以我们没有字典了。如果愿意,我们可以使用OrderedDict

1
2
from collections import OrderedDict
sorted_d  = OrderedDict(sorted(d.items(), key=lambda x: x[1]))

函数和列表理解

1
sorted_d = sorted((value, key) for (key,value) in d.items())

不过,他也对上述过程做了一个快速的基准测试。


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
months = {"January": 31,"February": 28,"March": 31,"April": 30,"May": 31,
         "June": 30,"July": 31,"August": 31,"September": 30,"October": 31,
         "November": 30,"December": 31}

def mykey(t):
   """ Customize your sorting logic using this function.  The parameter to
    this function is a tuple.  Comment/uncomment the return statements to test
    different logics.
   """

    return t[1]              # sort by number of days in the month
    #return t[1], t[0]       # sort by number of days, then by month name
    #return len(t[0])        # sort by length of month name
    #return t[0][-1]         # sort by last character of month name


# Since a dictionary can't be sorted by value, what you can do is to convert
# it into a list of tuples with tuple length 2.
# You can then do custom sorts by passing your own function to sorted().
months_as_list = sorted(months.items(), key=mykey, reverse=False)

for month in months_as_list:
    print month

由于需要保持与旧版本Python的向后兼容性,我认为OrderedDict解决方案是非常不明智的。您想要一些与Python 2.7和更老版本兼容的东西。

但是在另一个答案中提到的collections解决方案绝对是一流的,因为您要重新训练键和值之间的连接,这在dictionary中是非常重要的。

我不同意在另一个答案中给出的第一个选项,因为它扔掉了钥匙。

我使用了上面提到的解决方案(代码如下所示),并保留了对键和值的访问,在我的例子中,顺序是对值进行排序,但重要的是在对值进行排序之后对键进行排序。

1
2
3
4
5
6
7
8
from collections import Counter

x = {'hello':1, 'python':5, 'world':3}
c=Counter(x)
print c.most_common()


>> [('python', 5), ('world', 3), ('hello', 1)]

使用Python 3.2:

1
2
3
x = {"b":4,"a":3,"c":1}
for i in sorted(x.values()):
    print(list(x.keys())[list(x.values()).index(i)])

这个方法不使用lambda,在Python 3.6上运行良好:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
 # sort dictionary by value
d = {'a1': 'fsdfds', 'g5': 'aa3432ff', 'ca':'zz23432'}
def getkeybyvalue(d,i):
    for k, v in d.items():
        if v == i:
            return (k)

sortvaluelist = sorted(d.values())

# In >> Python 3.6+ << the INSERTION-ORDER of a dict is preserved. That is,
# when creating a NEW dictionary and filling it 'in sorted order',
# that order will be maintained.
sortresult ={}
for i1 in sortvaluelist:  
    key = getkeybyvalue(d,i1)
    sortresult[key] = i1
print ('=====sort by value=====')
print (sortresult)
print ('=======================')


除了使用内置模块等,我尝试手动解决它…首先,我做了一个函数,其工作是返回最小值的每一项的dict:

1
2
3
4
5
6
7
8
9
10
def returnminDict(_dct):
    dict_items = _dct.items()
    list_items = list(dict_items)
    init_items = list_items[0]
    for i in range(len(list_items)):
        if list_items[i][1] > init_items[1]:
           continue
        else:
           init_items = list_items[i]
    return init_items

其次,现在我们有一个函数,返回的项目有最小的值,然后我做一个新的dict,然后循环的dict:

1
2
3
4
5
6
7
def SelectDictSort(_dct):
    new_dict = {}
    while _dct:
        mindict = returnminDict(_dct)
        new_dict.update(dict((mindict,)))
        _dct.pop(mindict[0])
    return new_dict

我试试这个SelectDictSort({2: 5, 5: 1, 4: 3, 1: 1, 0: 1, 9: 2, 8: 2})会返回:

1
{0: 1, 1: 1, 5: 1, 8: 2, 9: 2, 4: 3, 2: 5}

嗯…我不知道哪一个是正确的,但我已经试过了……

(更新代码从retrun new_dctreturn new_dict)


1
2
3
4
>>> import collections
>>> x = {1: 2, 3: 4, 4:3, 2:1, 0:0}
>>> sorted_x = collections.OrderedDict(sorted(x.items(), key=lambda t:t[1]))
>>> OrderedDict([(0, 0), (2, 1), (1, 2), (4, 3), (3, 4)])

OrderedDictdict的子类。


我发现,与发布的其他解决方案相比,下面的函数执行得很好,即使是在大型字典中。

1
vsort = lambda d: sorted(d.iteritems(), key=lambda (k, v): v)

例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
data = {}
for i in range(10):
    data[i] = i if i % 2  else -i

print 'Original'
for k, v in data.items():
    print"k: %s v: %s" % (k, v)
print ''

print 'Value-sorted'
for k, v in vsort(data):
    print"k: %s v: %s" % (k, v)
print ''

输出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Original
k: 0 v: 0
k: 1 v: 1
k: 2 v: -2
k: 3 v: 3
k: 4 v: -4
k: 5 v: 5
k: 6 v: -6
k: 7 v: 7
k: 8 v: -8
k: 9 v: 9

Value-sorted
k: 8 v: -8
k: 6 v: -6
k: 4 v: -4
k: 2 v: -2
k: 0 v: 0
k: 1 v: 1
k: 3 v: 3
k: 5 v: 5
k: 7 v: 7
k: 9 v: 9

计时代码示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import numpy as np
from time import time
import operator
np.random.seed(0)

N = int(1e6)
x = {i: np.random.random() for i in xrange(N)}

t0 = -time()
sorted_0 = sorted(x.items(), key=operator.itemgetter(1))
t0 += time()

t1 = -time()
sorted_1 = vsort(x)
t1 += time()

print 'operator-sort: %f vsort: %f' % (t0, t1)
print sorted_0[:3]
print sorted_1[:3]

输出:

1
2
3
operator-sort: 2.041510 vsort: 1.692324
[(661553, 7.071203171893359e-07), (529124, 1.333679640169727e-06), (263972, 2.9504162779581122e-06)]
[(661553, 7.071203171893359e-07), (529124, 1.333679640169727e-06), (263972, 2.9504162779581122e-06)]