按照值列表重新排列Python字典

34

让我们考虑一个字典:

sample_dict={1:'r099',2:'g444',3:'t555',4:'f444',5:'h666'}

我想按照一个包含所需字典键顺序的列表重新排序这个字典。假设所需顺序列表如下:

desired_order_list=[5,2,4,3,1]

所以,我希望我的字典看起来像这样:

{5:'h666',2:'g444',4:'f444',3:'t555',1:'r099'}

如果我可以得到一个值的列表那也可以。也就是说,结果可以是这样的:

['h666','g444','f444','t555','r099']

我该如何以最简单的方式实现这个?


1
你是否实际使用了 collections.OrderedDict - jscs
1
我应该使用类似这样的代码吗:OrderedDict(sorted(sample_dict.items(), key=lambda t: [5,2,4,3,1]))。 - user699540
8个回答

40

Python 3.6及以上版本的答案

Guido已经确认从Python 3.7开始,字典将会被排序,而它们在3.6中已经作为实验性特性存在。该答案已经在Fastest way to sort a python 3.7+ dictionary中详细阐述。

在这种情况下,基于desired_order_list中包含的项,使用简单的字典推导式构建一个新的字典即可解决问题。

sample_dict = {1: 'r099', 2: 'g444', 3: 't555', 4: 'f444', 5: 'h666'}
print(sample_dict)
>>> {1: 'r099', 2: 'g444', 3: 't555', 4: 'f444', 5: 'h666'}

desired_order_list = [5, 2, 4, 3, 1]

reordered_dict = {k: sample_dict[k] for k in desired_order_list}
print(reordered_dict)
>>> {5: 'h666', 2: 'g444', 4: 'f444', 3: 't555', 1: 'r099'}

11

如果你正在使用 OrderedDict,你可以这样做

for key in [5,2,4,3,1]:
    my_ordered_dict[key] = my_ordered_dict.pop(key)

这会按照您想要的顺序重新插入有序字典中的所有内容,以便稍后可以执行相应操作。

my_ordered_dict.values()

按照你在问题中建议的列表获取。

如果你将重新插入的操作包装在 try: ...; except KeyError: pass 中,即使你的列表中并非所有键都存在,你也可以对一个 OrderedDict 进行重新排序。


5

除了在特殊情况下,如列表不完整且我们想要保留所有值并将其余部分留在最后,否则现有答案已经涵盖了问题:然后,在创建字典后,使用旧字典更新它以添加缺失的值:

    sample_dict = {1: 'r099', 2: 'g444', 3: 't555', 4: 'f444', 5: 'h666'}
    print(reordered_dict)
    # {1: 'r099', 2: 'g444', 3: 't555', 4: 'f444', 5: 'h666'}
    desired_order_list = [5, 2 ]
    reordered_dict = {k: sample_dict[k] for k in desired_order_list}
    print(reordered_dict)
    # {5: 'h666', 2: 'g444'}
    reordered_dict.update(sample_dict)
    print(reordered_dict)
    # {5: 'h666', 2: 'g444', 1: 'r099', 3: 't555', 4: 'f444'}

2

Python字典是无序的。

使用OrderedDict代替。


2
好的,但是我如何按特定顺序重新排序它们? - user699540
在Python 3.7+中,字典保留插入顺序。 - Paul Wintz

2
什么是为您重新排序字典的意义?字典本质上是无序数据结构-它们用于查找而不是顺序。您想以特定顺序迭代字典吗?那就使用您的desired_order_list:
for key in desired_order_list: 
  # d is the dictionary
  # do stuff with d[key]

正如其他人提到的那样,Python有一个OrderedDict(在2.7或3.x中),但我认为它不是你在这里需要的。重新排序它太低效了。最好的方法是将你的字典与所需顺序的键列表一起传递。
如果你仍然坚持要使用OrderedDict,请创建一个新的OrderedDict,在其中按desired_order_list的顺序插入值。

2

使用有序字典(OrderedDict)或者Eli's solution可能是一个不错的选择,但是为了参考,这里提供一种简单的方法来获取你想要的值列表:

[sample_dict[k] for k in desired_order_list]

如果您不能完全确定desired_order_list中的每个元素都是sample_dict中的键,请使用[sample_dict.get(k) ...][... for k in desired_order_list if k in sample_dict]。第一种方法将在缺失键时放入None,而第二种方法只包括在字典中的键的值。

1
这样做难道不更简单吗?
sample_dict={1:'r099',2:'g444',3:'t555',4:'f444',5:'h666'}
new_sample_dict={
    1: sample_dict[5],
    2: sample_dict[2],
    3: sample_dict[4],
    4: sample_dict[3],
    5: sample_dict[1]
}

1
这取决于列表的大小以及是否可以硬编码...但实际上,应该有一些情况下,这不仅更容易,而且更快(除非解释器非常聪明或非常愚蠢):) - ntg

0

使用Django提供的SortedDictfrom django.utils.datastructures import SortedDict)。SortedDict将其顺序存储在keyOrder属性中(它只是一个列表,因此您可以随时以任何方式重新排序它)。

如果您没有安装Django或不需要Django,则可以直接使用实现django.utils.datatstructures。它不依赖于Django的任何其他部分。


我使用Activestate Python,但在PyPm(http://code.activestate.com/pypm/sorteddict)中无法使用SortedDict包。 - user699540
只需从Django源代码中复制/粘贴实现http://code.djangoproject.com/browser/django/trunk/django/utils/datastructures.py#L99。 Django采用BSD许可证,因此即使您的应用程序是商业性质,也不会有问题。 - Imran

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