2016-02-17 147 views
2

我是Python的新手,目前正致力于解决问题以提高编程技能。我正在处理一个问题,我需要在Python中使用stable sort字典。请看以下细节:在Python中对字典值进行稳定排序

输入:

1 2 
16 3 
11 2 
20 3 
3 5 
26 4 
7 1 
22 4 

上面的命令,我加为两个lists k and v

k = ['1', '16', '11', '20', '3', '26', '7', '22'] 
v = ['2', '3', '2', '3', '5', '4', '1', '4'] 

我加入这两个列表成为一个字典把它作为一个键值对。我已使用OrderDict,因为我想让元素的顺序与它们在输入中的顺序相同。

from collections import OrderedDict 
d = OrderedDict(zip(k, v)) 

现在,我需要以按相反的顺序字典d相对于值。 (其实,我做一个稳定的排序,自sorted在Python是一个稳定的排序,我已经使用了来源:Here)对于:

s = sorted(d, key = itemgetter(1), reverse=True) 

预期输出:

3 5 
26 4 
22 4 
16 3 
20 3 
1 2 
11 2 
7 1 

但经过我实现了上面的sorted函数,我无法获得预期的输出。我得到IndexError: string index out of range

有人可以告诉我我在哪里做错了。我的方法错误或流程错误?你能否告诉我为什么我无法按预期得到产出?提前致谢。任何帮助将非常感激。

回答

4

下面是做到这一点的一种方法:

>>> sorted_kv = sorted(d.items(), key=lambda (k,v):int(v), reverse=True) 
>>> OrderedDict(sorted_kv) 
OrderedDict([('3', '5'), ('26', '4'), ('22', '4'), ('16', '3'), ... 

这需要的键/值对从字典中,对它们进行分类,并创建所需要订购新的有序字典。

key=参数sorted()指定要根据第二个项目的数值对这些对进行排序。

我需要调用int()的原因是您的字典将键和值都保留为字符串。按照原样排序它们将会起作用,但会生成lexicographic ordering而不是数字。

+0

感谢您的详细解释。我有几个查询 - 1.为什么字典将键和值保留为字符串,即使所有的值都是整数。 2.只有'd'代替'd.items'有什么区别吗?目的是什么。对不起,如果它听起来很愚蠢,但我只是想更好地理解。 – Dev

+0

@Dev 1)Python是强类型的。这意味着它不会在类型之间默默转换;你必须强制它通过铸造。有一些地方放松了一些地方(例如,不同类型之间的数学运算)。即使这些字符串只包含数字字符,它们仍然是字符串,除非明确地将它们转换为其他字符,否则将永远不会被视为任何不同的东西。 2)迭代只是'd'只会给你钥匙。 'd.items()'返回(key,value)的元组。基本上,它可以为您节省一些额外的字典。 – eestrada

4

您忘记使用.items()(Python3)或.iteritems()(Python2)来访问您的字典项目。

此外,您需要导入operator模块才能使用itemgetter()

因此,代码看起来像:

import operator 
from collections import OrderedDict 

k = ['1', '16', '11', '20', '3', '26', '7', '22'] 
v = ['2', '3', '2', '3', '5', '4', '1', '4'] 

d = OrderedDict(zip(k, v)) 

out = sorted(d.items(), key=operator.itemgetter(1), reverse=True) 

位置列表out是这样的:

[('3', '5'), ('26', '4'), ('22', '4'), ('16', '3'), ('20', '3'), ('1', '2'), ('11', '2'), ('7', '1')] 

为了打印您可以通过使用访问列表中的每个元组:

for i,k in out: 
    print(i,k) 

它给出了所需的输出:

3 5 
26 4 
22 4 
16 3 
20 3 
1 2 
11 2 
7 1 

我已经写了一个上面给出的代码的例子,可以在ideone.com找到。

+0

谢谢你,我确实尝试了,而我正在验证'但我得到了'字符串索引超出范围错误:(。和输出你给的不是预期的输出。我给了导入运算符 – Dev

+0

输出如果你想打印它,你只需要访问列表中的每一个元组,请看我更新的答案 – albert

+0

谢谢,它的工作,对不起,因为没有让你更早。请告诉我,如果我不使用'd.items()'并给出'd',会发生什么情况?它是否会迭代元素? – Dev

1

这是另一种方式来做到这一点:

from collections import OrderedDict 

k = ['1', '16', '11', '20', '3', '26', '7', '22'] 
v = ['2', '3', '2', '3', '5', '4', '1', '4'] 

d = OrderedDict(zip([int(x) for x in k], [int(y) for y in v])) # convert from string to int 
sorted_items = sorted(d.items()) 
sorted_items.reverse() 
s = OrderedDict(sorted_items) # new sorted ordered dict 
0

这是我对这项工作的想法勺:

k = ['1', '16', '11', '20', '3', '26', '7', '22'] 
v = ['2', '3', '2', '3', '5', '4', '1', '4'] 

# create a dictionary 
d = dict([(k[ind], v[ind]) for ind in range(0, len(k))]) 

for order in sorted(d, key=d.__getitem__, reverse=True): 
    print ("{}: {}".format(order, d[order])) 

输出:

3: 5 
26: 4 
22: 4 
16: 3 
20: 3 
11: 2 
1: 2 
7: 1 

但是我注意到,那在你的预期产出'1'在'11之前。这是有原因的吗?

相关问题