Python 中对字典值进行稳定排序

3
我是一位新手Python程序员,目前正在通过解决问题来提高我的编程技能。我正在解决一个问题,需要在Python中对一个字典进行稳定排序。请查看以下详细信息:
输入:
1 2
16 3
11 2
20 3
3 5
26 4
7 1
22 4

我已将上述输入添加到两个列表k和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进行排序。(实际上我需要进行稳定排序,由于Python中的sorted是一种稳定排序,因此我使用它。来源:这里)具体操作如下:

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个回答

6
这里是一种实现方法:
>>> 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'), ...

这将从字典中获取键/值对,对它们进行排序,并创建一个新的有序字典以满足要求的顺序。 sorted() 中的 key= 参数指定按第二项的数值对这些键值对进行排序。
我需要调用 int() 的原因是您的字典将键和值都保留为字符串。直接排序可以工作,但会产生字典序而不是数值排序。

感谢详细的解释。我有几个问题 - 1.即使所有的值都是整数,为什么字典仍然将键和值保留为字符串。2.只使用d而不是d.items会有什么区别?它的目的是什么。如果听起来很傻,请原谅,但我只是想更好地理解。 - sdgd
@Dev 1) Python是强类型的。这意味着它不会在类型之间默默地转换;您必须通过强制转换来实现。有些地方会放松一下(例如,不同类型之间的数学运算)。即使字符串只包含数字字符,它们仍然是字符串,除非您明确将它们转换为其他内容,否则永远不会被视为不同的内容。2)仅迭代'd'将只给您键。d.items()返回(key, value)元组。基本上,它可以为您节省一个额外的字典查找。 - eestrada

5
你忘记使用 .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找到。

谢谢,我确实在验证时尝试过那个了。但是我得到了“字符串索引超出范围”的错误 :(。而且你给出的输出结果并不是预期的输出结果。我使用了import操作符。 - sdgd
输出列表 out 按您想要的顺序排列。如果您想打印它,只需访问列表中的每个元组即可。请查看我的更新答案。 - albert
谢谢。它起作用了。很抱歉之前没有理解你的意思。如果我不使用 d.items() 而只是给出 d,会发生什么?它不会迭代元素吗? - sdgd
1
请查看此示例,以及文档这里这里 - albert

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”之前。这有什么原因吗?


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