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

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

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

注意:我在这里阅读了Stack Overflow问题如何按字典的值对字典列表进行排序?,并且可能会将我的代码更改为具有字典列表,但由于我真的不需要字典列表,我想知道是否有更简单的解决方案来按升序或降序排序。

4831664 次浏览

Python 3.7+或CPython 3.6

命令保留Python 3.7+中的插入顺序。在CPython 3.6中相同,但这是一个执行细节

>>> x = {1: 2, 3: 4, 4: 3, 2: 1, 0: 0}>>> {k: v for k, v in sorted(x.items(), key=lambda item: item[1])}{0: 0, 2: 1, 1: 2, 4: 3, 3: 4}

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

较旧的Python

对字典进行排序是不可能的,只能获得已排序字典的表示形式。字典本质上是无序的,但其他类型,如列表和元组,不是。所以你需要一个有序的数据类型来表示排序后的值,这将是一个列表——可能是一个元组列表。

例如,

import operatorx = {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 operatorx = {1: 2, 3: 4, 4: 3, 2: 1, 0: 0}sorted_x = sorted(x.items(), key=operator.itemgetter(0))

在Python3中,从不允许拆包开始,我们可以使用

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

如果你想要输出作为一个字典,你可以使用#0

import collections
sorted_dict = collections.OrderedDict(sorted_x)

字典无法排序,但您可以从中构建排序列表。

一个已排序的字典值列表:

sorted(d.values())

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

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

Hank Gay的回答相同:

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

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

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

您也可以创建一个“倒排索引”

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

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

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

您可以使用:

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

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

要按降序排序,只需添加reverse=True

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

输入:

d = {'one':1,'three':3,'five':5,'two':2,'four':4}a = sorted(d.items(), key=lambda x: x[1])print(a)

输出:

[('one', 1), ('two', 2), ('three', 3), ('four', 4), ('five', 5)]

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

>>> d = {"third": 3, "first": 1, "fourth": 4, "second": 2}
>>> for k, v in d.items():...     print "%s: %s" % (k, v)...second: 2fourth: 4third: 3first: 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的行为就像一个普通的字典:

>>> for k, v in d_sorted_by_value.items():...     print "%s: %s" % (k, v)...first: 1second: 2third: 3fourth: 4
>>> d_sorted_by_valueOrderedDict([('first': 1), ('second': 2), ('third': 3), ('fourth': 4)])

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

嗯,实际上可以“按字典值排序”。最近我不得不在Code Golf(Stack Overflow问题代码高尔夫:词频表)中这样做。简化后,问题是这样的:给定文本,计算每个单词遇到的频率,并显示热门单词列表,按频率递减排序。

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

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

然后你可以得到一个单词列表,按#0的使用频率排序-排序迭代字典键,使用单词出现的次数作为排序键。

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

我写这个详细的解释是为了说明人们通常所说的“我可以很容易地按键对字典进行排序,但我如何按值进行排序”-我认为最初的帖子试图解决这样一个问题。解决方案是根据值进行键列表,如上所示。

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

我也遇到过同样的问题,我是这样解决的:

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

(那些回答“It is not can to sort a的人没有阅读这个问题!事实上,“我可以根据键进行排序,但是我如何根据值进行排序?”显然意味着他想要一个根据值排序的键列表。)

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

这是代码:

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

使用通常非常方便。例如,您有一个字典,其中“name”作为键,“score”作为值,并且您想根据“score”进行排序:

import collectionsPlayer = 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)非常Python这样:

player = best[1]player.name'Richard'player.score7

dicts使用已排序值

from dicts.sorteddict import ValueSortedDictd = {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)]

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

$ python --versionPython 3.2.2
$ cat sort_dict_by_val_desc.pydictionary = 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.pyaina 5tuli 4joka 3sana 2siis 1

这适用于3.1. x:

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

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

如果值是数字,您也可以使用收藏中的#0

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:

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

您可以使用收款柜台。注意,这将适用于数值和非数值。

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

为了完整起见,我发布了一个使用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)]

在Python 2.7中,只需:

from collections import OrderedDict# regular unsorted dictionaryd = {'banana': 3, 'apple':4, 'pear': 1, 'orange': 2}
# dictionary sorted by keyOrderedDict(sorted(d.items(), key=lambda t: t[0]))OrderedDict([('apple', 4), ('banana', 3), ('orange', 2), ('pear', 1)])
# dictionary sorted by valueOrderedDict(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

享受;-)

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 tothis function is a tuple.  Comment/uncomment the return statements to testdifferent 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

另一个答案中提到的集合解决方案绝对是极好的,因为您保留了键和值之间的连接,这在字典的情况下非常重要。

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

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

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

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

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

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

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

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

这应该返回以下输出:

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

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

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

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

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

您可以使用跳过字典,它是一个按值永久排序的字典。

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

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

这是一个在#0和#1上使用zip的解决方案。此链接(在字典视图对象上)的几行是:

这允许使用zip()创建(value, key)对:对=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')]

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

from collections import OrderedDicta = 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或更高版本,请记住在打印后删除括号

使用Python 3.5

虽然我发现接受的答案很有用,但我也很惊讶它没有更新为引用标准库收藏模块中的OrderedDICT作为可行的现代替代方案-旨在解决此类问题。

from operator import itemgetterfrom 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作为排序函数:

# regular unsorted dictionaryd = {'banana': 3, 'apple':4, 'pear': 1, 'orange': 2}
# dictionary sorted by valueOrderedDict(sorted(d.items(), key=lambda t: t[1]))# OrderedDict([('pear', 1), ('orange', 2), ('banana', 3), ('apple', 4)])

python3.6开始,内置的字典将被排序

好消息,所以OP的原始用例从数据库中检索映射对,其中唯一的字符串id作为键,数值作为值进入内置的Python v3.6+字典,现在应该尊重插入顺序。

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

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 0bar 1baz 42

按v的值排序。

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

bar 1foo 0baz 42

详情:

正如Raymond Hettinger在2012年提出的(参见主题为“具有更快迭代的更紧凑字典”的python-dev上的邮件),以及现在(2016年)Victor Stiner在邮件中宣布的主题为”“Python 3.6字典变得紧凑并获得私有版本;关键字变得有序”的python-dev,由于Python 3.6中问题27350“紧凑而有序的判决书”的修复/实现,我们现在可以使用内置字典来维护插入顺序!!

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

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

  • 关键字参数和
  • (中间)字典存储

第一个是因为它在某些情况下简化了函数和方法的执行。

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

Raymond Hettinger亲切地留档解释“Python 3.6字典背后的技术”-来自他的旧金山Python Meetup Group演讲2016-DEC-08。

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

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

正如@ajcr正确地指出的那样:“这个新实现的顺序保持方面被认为是一个实现细节,不应该被依赖。”(从Whatsnew36开始)不是挑剔,的引用有点悲观;-)。它继续作为“(这可能会在未来发生变化,但希望在更改语言规范以强制所有当前和未来的Python实现的顺序保持语义学之前,在语言中有几个版本中使用这种新的字典实现;这也有助于保持与旧版本语言的向后兼容,其中随机迭代顺序仍然有效,例如Python 3.5)。

因此,就像在某些人类语言(例如德语)中一样,用法塑造了语言,现在已经在Whatsnew36中声明了……。

更新2017-12-15:

邮件到python-dev列表中,Guido van Rossum声明:

让它这样做。“迪克特保持插入顺序”是裁决。谢谢!

因此,CPython 3.6版本中的字典插入排序的副作用现在已经成为语言规范的一部分(而不仅仅是一个实现细节)。

此方法不会使用lambda,并且在Python 3.6上运行良好:

 # sort dictionary by valued = {'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] = i1print ('=====sort by value=====')print (sortresult)print ('=======================')

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

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)

正如Diletter所指出的,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 tuplestry: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 TypeErrorexcept (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_listelif isinstance(iterable, tuple):sorted_list = tuple(_sort(None))return sorted_listelif isinstance(iterable, dict):if sort_on == 'keys':sorted_dict = _sort(0)return sorted_dictelif sort_on == 'values':sorted_dict = _sort(1)return sorted_dictelif 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")

我刚从Python为每个人学到了一个相关的技能。

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

# Assume dictionary to be:d = {'apple': 500.1, 'banana': 1500.2, 'orange': 1.0, 'pineapple': 789.0}
# Create a temporary listtmp = []
# Iterate through the dictionary and append each tuple into the temporary listfor key, value in d.items():tmptuple = (value, key)tmp.append(tmptuple)
# Sort the list in ascending ordertmp = sorted(tmp)
print (tmp)

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

tmp = sorted(tmp, reverse=True)

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

# Assuming the dictionary looks liked = {'apple': 500.1, 'banana': 1500.2, 'orange': 1.0, 'pineapple': 789.0}# One-liner for sorting in ascending orderprint (sorted([(v, k) for k, v in d.items()]))# One-liner for sorting in descending orderprint (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')]

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

>>> 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留档表示:

在3.7版更改:字典顺序保证是插入的此行为是3.6中CPython的实现细节。

除了使用内置模块等,我尝试手动解决它…

第一,我做了一个函数,它的工作是返回字典的每个项目的最小值:

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]:continueelse:init_items = list_items[i]return init_items

第二,现在我们有了一个函数,它返回一个具有最小值的项目。然后我做了一个新的字典并在字典上循环:

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})。它会返回:

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

嗯…我不知道哪个是正确的,但这是我试过的…