根据列表中的元素对值为列表的字典进行排序

54
我想按照每个列表中第三个项目的值对一个包含列表的字典进行排序。当值只是单个数字或字符串时,按值对字典进行排序很容易,但是这个列表使我感到困惑。
例子:
myDict = {'item1': [7, 1, 9], 'item2': [8, 2, 3], 'item3': [9, 3, 11] }

我希望能够按照每个列表中第三个值的顺序迭代字典,即item2item1,然后是item3

4个回答

69

以下是一种方法:

>>> sorted(myDict.items(), key=lambda e: e[1][2])
[('item2', [8, 2, 3]), ('item1', [7, 1, 9]), ('item3', [9, 3, 11])]

sorted函数的key参数可以为列表中的每个元素提供一个排序关键字。

要遍历此列表中的键/值,您可以使用类似以下方式的代码:

>>> for key, value in sorted(myDict.items(), key=lambda e: e[1][2]):
...   print key, value
... 
item2 [8, 2, 3]
item1 [7, 1, 9]
item3 [9, 3, 11]

1
我一问完问题就恍然大悟,基本上想到了相同的解决方法,只是没有使用 lambda(还没学过)。我自己写了一个 cmp 函数,它接受来自 dict.items() 的元组并返回结果。同样的事情,只是用不同的方式写出来。非常感谢您的快速回复! - jay
很棒的解决方案。我喜欢sorted()的简洁性。 - Evan Fosmark
10
我认为这样更清晰一些:sorted(myDict.items(), key=lambda (k, v): v[2]) - Roberto Bonvallet
@jay,就性能而言,key=比cmp=好得多——此外,SO的礼仪建议您接受这个答案,而不仅仅口头表达感谢! - Alex Martelli
“除了 lambda(还没学过它们)之外,这是一个很好的观点。尽可能避免使用 lambda。可以使用普通的函数定义来实现,这通常比 lambda 更清晰。” - S.Lott
@jay:在Python 3中不再支持cmp=。 - newacct

4
您提出了两个截然不同的要求:
1. “我想要做的是对一个字典列表进行排序…” 2. “我想按照顺序遍历字典…”
第一个要求在定义上是不可能的,因为排序意味着以某种顺序重新排列。Python 字典本来就是无序的。第二个要求可能存在,但实现起来非常困难。
您可以这样做:
1. 复制字典内容(这将是相当无序的) 2. 对其进行排序 3. 遍历排序后的结果,而您已经有了两种解决方案。顺便说一下,使用“键”而不是“比较”更好,详见 sorted “列表中的第三项”对我来说听起来像“元组中的第三项”,而“e[1][2]”则有点奇怪……您可以考虑使用命名元组代替列表,详见 命名元组工厂 如果您需要频繁地对大型数据集进行提取、排序和处理,建议您考虑使用 Python 自带的 sqlite3 模块。
create table ex_dict (k text primary key, v0 int, v1 int, v2 int);
insert into ex_dict values('item1', 7, 1, 9);
-- etc etc 
select * from ex_dict order by v2;

值得注意的是,自Python 3.7以来,字典实际上确实维护了元素的插入顺序。 - Tomerikoo

3
如John Machlin所说,你实际上不能对Python字典进行排序。
然而,你可以创建一个键的索引,这些键可以按任何顺序排序。
用于按任何其他标准排序的首选Python模式(惯用法)称为“装饰-排序-去除装饰”(DSU)。在这个惯用法中,你创建一个临时列表,其中包含元组,其中包含你的键,后跟你的原始数据元素,然后调用该列表上的常规.sort()方法(或者,在更近期的Python版本中,只需将你的装饰包装在调用sorted()内置函数的中即可)。然后你移除“装饰”。
之所以通常比将比较函数传递给.sort()方法要好,是因为Python的内置默认排序代码(默认情况下为编译的C Python)在默认情况下非常快速和高效,但在非默认情况下必须多次调用Python对象代码时要慢得多。因此,通常最好遍历数据创建可以传递给默认排序例程的数据结构。
在这种情况下,你应该能够使用类似以下的内容:
[y[1] for y in sorted([(myDict[x][2], x) for x in myDict.keys()])]

这是一个列表推导式,它从内部列表推导式返回的元组排序列表中执行未装饰操作。 内部推导式创建了一个元组集,其中包含您所需的排序键(列表的第3个元素)和与排序键对应的字典键。 myDict.keys()是Python字典的方法,它以基础实现选择的任何顺序返回所有有效键的列表 --- 可能是哈希的简单迭代。

更详细的方法可能更容易阅读:

temp = list()
for k, v in myDict.items():
    temp.append((v[2],))
temp.sort()
results = list()
for i in temp:
    results.append(i[1])

通常你应该迭代地建立这样的代码,在解释器中使用小数据样本。建立“decorate”表达式或函数。然后将其包装在sorted()的调用中。然后建立undecorate表达式(通常与我在这里展示的一样简单)。

(1) 你可以将decorate-sort-undecorate与使用cmp参数进行比较;key参数的引入削减了DSU方法的很大一部分领域。 (2) 你的解决方案让OP得到了一个字典键列表...为了得到他想要的,他还需要再遍历一次字典项。 (3) 你那啰嗦的方式有个错别字:s/v[2],/v[2], k/。 - John Machin

0
现在你可以这样做:返回一个字典本身。布尔值用于确定顺序是升序还是降序。
sorted_dict = dict(sorted(myDict.items(), key=lambda item: item[1][2], reverse=True))

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