根据列表中的元素对字典(值为列表)进行排序
我想按照每个列表中的第三个元素来给一个字典排序。给字典按值排序的时候,如果值只是一个数字或字符串,那还挺简单的,但这个列表的事情让我感到困惑。
举个例子:
myDict = {'item1': [7, 1, 9], 'item2': [8, 2, 3], 'item3': [9, 3, 11] }
我希望能够按照每个列表中的第三个值来遍历这个字典,在这个例子中,就是 item2
,item1
然后是 item3
。
4 个回答
正如约翰·马赫林所说,实际上你不能对一个Python字典进行排序。
不过,你可以创建一个键的索引,这个索引可以按照你喜欢的任何顺序进行排序。
在Python中,按照其他标准排序的推荐方法叫做“装饰-排序-去装饰”(DSU)。在这个方法中,你会创建一个临时列表,这个列表包含了你的键和原始数据元素的元组,然后对这个列表调用普通的.sort()方法(或者在更新版本的Python中,直接用sorted()这个内置函数来处理)。最后,你再去掉这些“装饰”。
之所以通常推荐这种方法,而不是直接给.sort()方法传递比较函数,是因为Python内置的默认排序代码(在普通的C Python中是编译成C的)在默认情况下非常快和高效,但在非默认情况下,如果需要多次调用Python对象代码,就会慢得多。因此,通常最好是先遍历数据,创建可以传递给默认排序例程的数据结构。
在这种情况下,你可以使用类似这样的代码:
[y[1] for y in sorted([(myDict[x][2], x) for x in myDict.keys()])]
... 这段代码是一个列表推导式,它从返回的元组排序列表中去掉了装饰。内部的推导式创建了一组元组,包括你想要的排序键(列表的第三个元素)和与排序键对应的字典键。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])
通常你应该在解释器中使用小数据样本逐步构建这样的代码。先构建“装饰”表达式或函数。然后把它包裹在sorted()的调用中。最后构建去装饰的表达式(通常和我这里展示的差不多简单)。
你提到的两个需求其实有点不一样:
- “我想对一个字典里的列表进行排序...”
- “我想按照某种顺序遍历这个字典...”
第一个需求从定义上来说是做不到的——排序意味着要重新排列顺序。而Python的字典本身就是无序的。第二个需求虽然有点可能,但实现起来非常不容易。
你可以做的是:
- 先复制字典里的内容(这会是无序的)
- 对复制的内容进行排序
- 遍历排序后的结果——而且你已经有两种方法可以做到这一点。顺便说一下,使用“key”而不是“cmp”的方法更好;可以参考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;
这里有一种方法可以做到这一点:
>>> 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]