首页 > 解决方案 > 在 Python 3 中,如何在排行榜中查找排名并将其转换为字典?

问题描述

我有一个嵌套的排行榜​​,如下所示:

[[100, 100, 50, 40, 40, 20, 10, 5], [100, 100, 50, 40, 40, 25, 20, 10]]

我想用密集顺序排名方法在这个排行榜中找到排名。https://en.wikipedia.org/wiki/Ranking#Dense_ranking_.28.221223.22_ranking.29

我想使用排名并将其转换为字典,但分数需要保留为键,而排名作为值,如下所示:

[{100:1,100:1,50:2,40:3,40:3,20:4,10:5,5:6},{100:1,100:1,50:2,40:3,40:3,25:4,20:5,10:6}]

如何使用 Python3 实现这一点?

标签: pythonpython-3.xlistdictionary

解决方案


如前所述,您预期的数据结构不是字典,因为它包含重复键。相反,您可以创建一个元组列表。您可以使用计数器对象和字典来跟踪看到的项目及其各自的索引以创建该元组。

以下函数是上述方法的可理解实现,它在一次迭代中创建预期结果。

In [38]: from itertools import count
In [38]: def ranker(lst):
    ...:     for sub in lst:
    ...:         seen = {}
    ...:         c = count()
    ...:         next(c)
    ...:         ss = []
    ...:         for j in sub:
    ...:             try:
    ...:                 ind = seen[j]
    ...:             except KeyError:
    ...:                 ind = seen[j] = next(c)
    ...:             ss.append((j, ind))
    ...:         yield ss

演示:

In [39]: lst
Out[39]: [[100, 100, 50, 40, 40, 20, 10, 5], [100, 100, 50, 40, 40, 25, 20, 10]]

In [40]: list(ranker(lst))
Out[40]: 
[[(100, 1), (100, 1), (50, 2), (40, 3), (40, 3), (20, 4), (10, 5), (5, 6)],
 [(100, 1), (100, 1), (50, 2), (40, 3), (40, 3), (25, 4), (20, 5), (10, 6)]]

现在,一种更加 Pythonic 但有点模糊的方法是使用列表理解中的方法而不是使用countertry-except块,甚至是列表和附加dict.setdefault(),如下所示:

In [43]: def ranker(lst):
    ...:     for sub in lst:
    ...:         seen = {}
    ...:         yield [(j, seen.setdefault(j, len(seen) + 1)) for j in sub]

dict.setdefault()如果第一个参数存在于字典中,则该方法返回相应的值,否则使用第二个参数 ( len(seen) + 1) 作为其值更新自身并返回它。

演示:

In [44]: list(ranker(lst))
Out[44]: 
[[(100, 1), (100, 1), (50, 2), (40, 3), (40, 3), (20, 4), (10, 5), (5, 6)],
 [(100, 1), (100, 1), (50, 2), (40, 3), (40, 3), (25, 4), (20, 5), (10, 6)]]

推荐阅读