提问



我有一个从数据库中的两个字段读取的值字典:字符串字段和数字字段。字符串字段是唯一的,因此这是字典的关键字。


我可以对键进行排序,但是如何根据值进行排序?


注意:我已阅读Stack Overflow问题如何按字典中的字典值对字典列表进行排序?并且可能会将我的代码更改为包含字典列表,但由于我不是真的如果有一个更简单的解决方案,我需要一个我想知道的词典列表。

最佳参考


不可能对字典进行排序,只是为了获得已排序的字典的表示。字典本质上是无序的,但其他类型(如列表和元组)则不是。因此,您需要一个有序数据类型来表示排序值,这将是一个列表 - 可能是元组列表。


例如,


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


对于那些希望按键而不是值进行排序的人:


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


在Python3中,因为不允许解包
import operator
x = {1: 2, 3: 4, 4: 3, 2: 1, 0: 0}
sorted_x = sorted(x.items(), key=operator.itemgetter(1))
我们可以使用


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

其它参考1


简单如下:sorted(dict1, key=dict1.get)



嗯,实际上可以做一个按字典值排序。最近我必须在Code Golf(Stack Overflow问题 Code golf:Word频率图)中这样做。简而言之,问题就是这样:给定一个文本,计算每个单词遇到的频率,并显示顶部单词列表,按频率降低排序。


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


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


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


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


我正在写这个详细的解释,以说明人们通常所说的我可以轻松地按键排序字典,但我如何按价值排序 - 我认为OP试图解决这个问题。解决方案是根据值对键进行排序,如上所示。

其它参考2


你可以使用:


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


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

其它参考3


不能对Dicts进行排序,但您可以从它们构建排序列表。


dict值的排序列表:


sorted(d.values())


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


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

其它参考4


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


>>> 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}


要从原始字典创建新的有序字典,请按值排序:


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


OrderedDict的行为类似于普通的dict:


>>> 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)])

其它参考5


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


虽然我发现接受的答案很有用,但我也感到惊讶的是,它没有被更新以引用标准库集合模块中的 OrderedDict 作为可行的现代替代方案 - 设计解决这类问题。[89]


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作为sort函数:[90]


# 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)])

其它参考6


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


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


首先排序得分最低:


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


首先排序得分最高:


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


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


player = best[1]
player.name
    'Richard'
player.score
    7

其它参考7


和汉克盖伊的回答几乎相同;



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



或者根据John Fouhy的建议进行优化;



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


其它参考8


从Python 3.6开始,内置的dict将被订购



好消息,所以OP的原始用例是从具有唯一字符串ID的数据库中检索的映射对作为键和数值作为值到内置Python v3.6 + dict,现在应该遵循插入顺序。[92]


如果说从数据库查询得到的两个列表表达式如下:


SELECT a_key, a_value FROM a_table ORDER BY a_value;


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


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


允许稍后输出为:


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


在这种情况下产生(对于新的Python 3.6+内置字典!):


foo 0
bar 1
baz 42


每个v值相同的排序。


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


bar 1
foo 0
baz 42


详细说明:



正如Raymond Hettinger在2012年提出的那样(参见python-dev上的邮件主题为更紧凑的词典和更快速的迭代),现在(2016年)由Victor Stinner在邮件中宣布python-dev主题为Python 3.6 dict紧凑并获得私有版本;关键字变得有序由于问题27350的修复/实现紧凑和有序的dict在Python 3.6中我们现在可以使用内置的dict来维护插入顺序!! [[[93] [94] [95]


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


是时候重新考虑我们的编码习惯,不要错过稳定订购的可能性:



  • 关键字参数和

  • (中间)dict存储



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


第二,因为它鼓励更容易使用dict作为处理管道的中间存储。


Raymond Hettinger亲切地提供了解释Python 3.6词典背后的技术的文档 - 来自旧金山Python Meetup Group 2016-DEC-08的演示文稿。[96]


也许相当一些Stack Overflow高度装饰的问答页面将收到此信息的变体,许多高质量的答案也需要每个版本更新。


警告Emptor(但也见下面更新2017-12-15):



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


因此,在一些人类语言(例如德语)中,用法形成了语言,现在已经宣布了......在whatsnew36。[98]


更新2017-12-15:



在发往python-dev列表的邮件中,Guido van Rossum宣称:[99]



  这样做。 Dict保持插入秩序是裁决。谢谢!



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

其它参考9


鉴于字典


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


排序


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


结果


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


您可以使用lambda函数按值对事物进行排序,并将它们存储在变量中,在本例中为 sred e 原始字典。


希望有所帮助!

其它参考10


我遇到了同样的问题,我这样解决了:


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


(回答不可能对词典进行排序的人没有读到这个问题!事实上,我可以对键进行排序,但是如何根据值进行排序?显然意味着他想要一个列表键根据其值的值排序。)


请注意,订单定义不明确(具有相同值的键将在输出列表中以任意顺序排列)。

其它参考11


在Python 2.7中,只需执行以下操作:


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 [100]


请享用 ;-)

其它参考12


这是代码:


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 "\n>> Rofl sort >>"
for foo in sorted(origin_list, key=operator.itemgetter("rofl")):
    print foo

print "\n>> Rank sort >>"
for foo in sorted(origin_list, key=operator.itemgetter("rank")):
    print foo


结果如下:


原始


{'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


{'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}


等级


{'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}

其它参考13


如果值是数字,您还可以使用集合中的计数器


from collections import Counter

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


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

其它参考14


从技术上讲,字典不是序列,因此无法排序。你可以做点什么


sorted(a_dictionary.values())


假设表现不是很大。

其它参考15


您可以使用collections.Counter。请注意,这适用于数字和非数字值。[101]


>>> 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)])

其它参考16


您也可以创建倒排索引


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


现在您的逆值具有值;每个值都有一个适用键列表。


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

其它参考17


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


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


如果想要按键对字典进行排序,可以执行以下操作:


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


这应该返回以下输出:


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


另一方面,如果想按值对字典进行排序(如问题中所述),可以执行以下操作:


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


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


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

其它参考18


您可以使用skip dict,它是一个按值永久排序的字典。[102]


>>> 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(),那么您将按值按顺序迭代。


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

其它参考19


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


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


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


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


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


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

其它参考20


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

其它参考21


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


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函数


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

其它参考22


这是在d.values()d.keys()上使用zip的解决方案。此链接的几行(在Dictionary视图对象上)是:[104]



  这允许使用zip()创建(值,键)对:pairs=zip(d.values(),d.keys())。



所以我们可以做到以下几点:


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')]

其它参考23


使用来自dicts的 ValueSortedDict :[105]


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)]

其它参考24


我想出了这个,


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()


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


或者试试collections.OrderedDict!


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]))

其它参考25


您可以使用Python的排序函数


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


因此你可以使用:


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


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

其它参考26


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


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





如果您没有Python 2.7或更高版本,那么您可以做的最好是迭代生成器函数中的值。 (这里有2.4和2.6的OrderedDict,但是[107]


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





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.)





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或更高版本,请记得在打印后删除括号

其它参考27


迭代一个字典并按其值按降序排序:


$ 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

其它参考28


正如Dilettant所指出的,Python 3.6现在将保持订单!我以为我会共享一个我编写的函数,它可以简化迭代(元组,列表,字典)的排序。在后一种情况下,您可以对键或值进行排序,并且可以将数值比较考虑在内。 >仅适用于>=3.6!


当你尝试在一个包含例如的迭代时使用sorted字符串以及整数,sorted()将失败。当然你可以用str()强制进行字符串比较。但是,在某些情况下,您希望进行实际数字比较,其中12小于20(在字符串比较中不是这种情况)。所以我想出了以下内容。当您想要显式数字比较时,您可以使用标志num_as_num,它将尝试通过尝试将所有值转换为浮点数来进行显式数字排序。如果成功,它将进行数字排序,否则它将采用字符串比较。


欢迎评论改进或推送请求。[109]


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")

其它参考29


如果您的值是整数,并且您使用的是Python 2.7或更高版本,则可以使用collections.Counter而不是dictmost_common方法将为您提供所有项目,按值排序。[110]