按值对字典中的字典进行排序

23

我有这个字典:

statuses = {
            'pending' : {'status_for':'all', 'position':1},
            'cancelled' : {'status_for':'all','position':2},
            'approved' : {'status_for':'owner', 'position':1},
            'rejected - owner' : {'status_for':'owner', 'position':2},
            'accepted' : {'status_for':'dev', 'position':1},
            'rejected - developer' : {'status_for':'dev', 'position':3},
            'closed' : {'status_for':'dev', 'position':5},
            }

我还有一个函数来获取所有ownerdevstatus_for值,并将其放入PyQt QComboBox中,函数如下:

```python def get_status_for(self, owner=True, dev=True): status_for_list = [] if owner: status_for_list.extend([x["status_for"] for x in self.owner_data]) if dev: status_for_list.extend([x["status_for"] for x in self.dev_data])
unique_status_for = sorted(set(status_for_list)) self.status_for_combobox.clear() for status_for in unique_status_for: self.status_for_combobox.addItem(status_for) ```
for s in statuses:
            if statuses[s]['status_for'] == "dev" or statuses[s]['status_for'] == "all":
                cb_developer_status.addItem(s.capitalize(), s)   

我想按照 position 值来排序这些内容,有什么好的方法可以做到这一点,这样当我填充下拉框时就可以按照预定义的顺序呈现了?

我意识到上面的代码片段正在检查 'dev' 和 'all' 两者,我的假设是我需要通过字典循环两次来获取我希望的两个不同块(即'all'出现在'dev'之前)。

我看到了 这篇文章,但我不知道如何将这个答案转换为一个字典的字典。

4个回答

40

这个方案可行吗?类似于您所链接的帖子,它使用sorted函数的key参数来提供自定义排序顺序。iteritems()方法返回一个包含键值对的元组,因此可以将其传递给lambda (x, y): y['position'],其中y['position']是值(您的嵌套字典,以状态为键),而position是您想排序的项。

In [35]: statuses = {
            'pending' : {'status_for':'all', 'position':1},
            'cancelled' : {'status_for':'all','position':2},
            'approved' : {'status_for':'owner', 'position':1},
            'rejected - owner' : {'status_for':'owner', 'position':2},
            'accepted' : {'status_for':'dev', 'position':1},
            'rejected - developer' : {'status_for':'dev', 'position':3},
            'closed' : {'status_for':'dev', 'position':5},
            }

In [44]: for s in sorted(statuses.iteritems(), key=lambda (x, y): y['position']):
   ....:     print s
   ....:
   ....:
('accepted', {'position': 1, 'status_for': 'dev'})
('approved', {'position': 1, 'status_for': 'owner'})
('pending', {'position': 1, 'status_for': 'all'})
('rejected - owner', {'position': 2, 'status_for': 'owner'})
('cancelled', {'position': 2, 'status_for': 'all'})
('rejected - developer', {'position': 3, 'status_for': 'dev'})
('closed', {'position': 5, 'status_for': 'dev'})

1
key=lambda (k,v): v['position']使代码更易于阅读+1。 - Jon Clements
@JonClements 无可辩驳 :) 已更改。 - RocketDonkey
31
请注意,在Python 3中,key=lambda(k,v): v['position'] 必须写成 key=lambda k_v: k_v[1]['position'] - dano
11
在Python 3中,dict.iteritems()被改为dict.items():https://dev59.com/q10a5IYBdhLWcg3wW3nN - Jeppe
5
你们两个都是对的。在 python3 中测试成功了 sorted(statuses.items(), key=lambda k_v: k_v[1]['position']) - gies0r

11
In [232]: statuses = {                                                                  
            'pending' : {'status_for':'all', 'position':1},
            'cancelled' : {'status_for':'all','position':2},
            'approved' : {'status_for':'owner', 'position':1},
            'rejected - owner' : {'status_for':'owner', 'position':2},
            'accepted' : {'status_for':'dev', 'position':1},
            'rejected - developer' : {'status_for':'dev', 'position':3},
            'closed' : {'status_for':'dev', 'position':5},
            }

In [235]: sorted(statuses,key=lambda x:statuses[x]['position'])
Out[235]: 
['accepted',
 'approved',
 'pending',
 'rejected - owner',
 'cancelled',
 'rejected - developer',
 'closed']

或者使用operator.getitem()

In [260]: from operator import *

In [261]: sorted(statuses.items(),key=lambda x:getitem(x[1],'position'))
Out[261]: 
[('accepted', {'position': 1, 'status_for': 'dev'}),
 ('approved', {'position': 1, 'status_for': 'owner'}),
 ('pending', {'position': 1, 'status_for': 'all'}),
 ('rejected - owner', {'position': 2, 'status_for': 'owner'}),
 ('cancelled', {'position': 2, 'status_for': 'all'}),
 ('rejected - developer', {'position': 3, 'status_for': 'dev'}),
 ('closed', {'position': 5, 'status_for': 'dev'})]

1

我知道现在回答这个问题有些晚了,但是我遇到了一个类似的问题,几乎和你拥有的字典结构相同,这是我解决它的方法:

我的结构如下:

dictOfDicts = {
   0: {'id': 3, 'title': 'hello'}, 
   1: {'id': 1, 'title': 'hi'},
   2: {'id': 2, 'title': 'aloha'},
}

我想让您将其订购成这个样子:
dictOfDicts = {
   0: {'id': 1, 'title': 'hi'}, 
   1: {'id': 2, 'title': 'aloha'}
   2: {'id': 3, 'title': 'hello'},
}

即使用内部的'id'项来改变外部项目的顺序。


因此,我首先使用sorted()在外部项目中获取新索引列表:

newIndex = sorted(dictOfDicts, key=lambda x: dictOfDicts[x]['id'])

现在newIndex包含了列表中的新顺序

#output
newIndex = [1,2,0]

然后我使用newIndex来改变外部项目的顺序:

dictOfDicts = {newIndex[k]: dictOfDicts[k] for k in newIndex}

如果有人想知道发生了什么,请在评论中告诉我,我不希望答案比必要的更长,因为问题已经得到解答。


1
补充一下,如果您的父字典的键是字符串而不是整数,则在按正确顺序重建字典时,您将想要使用以下行: dictOfDicts = {k: dictOfDicts[k] for k in newIndex}这是因为您无法在字符串上切片列表(newIndex变量是一个列表)。 - jjasper

0
这是另一种最佳方法来对Python的字典进行排序,即字典的字典。
# define dictionary data
dictOfDict = {
    'mainkey1': {'subkey1':'a', 'subkey2': 100},
    'mainkey2': {'subkey1':'b', 'subkey2': 50},
    'mainkey3': {'subkey1':'c', 'subkey2': 500},
    'mainkey4': {'subkey1':'d', 'subkey2': 250}
}

# define another dictionary to store sorted dictionary data
sorted_dictOfDict = dict()

# sort mainkeys by subkey2 :: outputs a list of mainkeys from original dict
sorted_keys = sorted(dictOfDict, key=lambda x:dictOfDict[x]['subkey2'], reverse=False)

# use the sorted list of keys to copy original dict to sorted dict (key-val by key-val)
for key in sorted_keys:
    sorted_dictOfDict[key] = dictOfDict[key]

# clear original dict and copy sorted dict back to original
dictOfDict.clear()
dictOfDict = sorted_dictOfDict.copy()

print(dictOfDict)

输出:

dictOfDict = {
    'mainkey2': {'subkey1':'b', 'subkey2': 50},
    'mainkey1': {'subkey1':'a', 'subkey2': 100},
    'mainkey4': {'subkey1':'d', 'subkey2': 250},
    'mainkey3': {'subkey1':'c', 'subkey2': 500}
}

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