【问题标题】:Python Ranking Dictionary Return RankPython排名字典返回排名
【发布时间】:2019-09-17 21:00:16
【问题描述】:

我有一本 python 字典:

x = {'a':10.1,'b':2,'c':5}

如何进行排名并返回排名值?喜欢回来:

res = {'a':1,c':2,'b':3}

谢谢

编辑:

我不想进行排序,因为这可以通过 python 中的sorted 函数来完成。我更多地考虑让排名值从最高到最低......所以在排序后用它们的位置替换字典值。 1 表示最高,3 表示最低。

【问题讨论】:

  • 什么是排名值? b的值如何变成3
  • 排名值是指key和value在字典中的位置,类似于索引数组?
  • 1 表示最高值,3 表示最低值
  • 那么按值对所有内容进行排序?
  • 我最好的猜测是有人没有意识到你可以使用排序来做你想要的排名,看到了sorted 的使用,并且你说“我不想排序” ,并认为答案一定是错误的。

标签: python


【解决方案1】:

如果我理解正确,您可以简单地使用sorted 获取订单,然后使用enumerate 对其进行编号:

>>> x = {'a':10.1, 'b':2, 'c':5}
>>> sorted(x, key=x.get, reverse=True)
['a', 'c', 'b']
>>> {key: rank for rank, key in enumerate(sorted(x, key=x.get, reverse=True), 1)}
{'b': 3, 'c': 2, 'a': 1}

请注意,这假定排名是明确的。如果您有平局,则平局键之间的排名顺序将是任意的。使用类似的方法也很容易处理,例如,如果您希望所有绑定的键具有相同的等级。我们有

>>> x = {'a':10.1, 'b':2, 'c': 5, 'd': 5}
>>> {key: rank for rank, key in enumerate(sorted(x, key=x.get, reverse=True), 1)}
{'a': 1, 'b': 4, 'd': 3, 'c': 2}

但是

>>> r = {key: rank for rank, key in enumerate(sorted(set(x.values()), reverse=True), 1)}
>>> {k: r[v] for k,v in x.items()}
{'a': 1, 'b': 3, 'd': 2, 'c': 2}

【讨论】:

  • 在最后一种情况下,我认为b 应该是4,因为dc 绑定在2 位置。保持数字正确b 应该是4。如何做到这一点?
  • @beta:这并不是关于什么是正确的观点,只是你想要的不同的东西。 :-) 但是如果您有新问题,请打开一个新问题——没有人会在旧评论中看到它。
  • 意见与否,通常是这样做的。查看所有运动排名。如果有 2 个人在同一个位置并列,则下一个分配的位置是 +1。无论如何,可能有一些用例,这不是那么有用。谢谢,如果我在其他地方找不到答案,我会提出一个新问题。另见:stackoverflow.com/questions/23641054/…
  • @beta:这越来越傻了,但是上面描述了三种不同的排名方案。你想要第四个,这很好,但实际上不是问题。
【解决方案2】:

使用scipy.stats.rankdata:

[ins] In [55]: from scipy.stats import rankdata                                                                                                                                                        

[ins] In [56]: x = {'a':10.1, 'b':2, 'c': 5, 'd': 5}                                                                                                                                                   

[ins] In [57]: dict(zip(x.keys(), rankdata([-i for i in x.values()], method='min')))                                                                                                                   
Out[57]: {'a': 1, 'b': 4, 'c': 2, 'd': 2}

[ins] In [58]: dict(zip(x.keys(), rankdata([-i for i in x.values()], method='max')))                                                                                                                   
Out[58]: {'a': 1, 'b': 4, 'c': 3, 'd': 3}

@beta, @DSM scipy.stats.rankdata 有一些其他的“方法”来处理关系可能更适合你想要处理关系。

【讨论】:

  • 顺便说一句,排名是numpy.int64,而不是ints,以防万一。
【解决方案3】:

首先按字典中的值排序,然后分配排名。确保您反向排序,然后重新创建带有排名的字典。

来自上一个答案:

import operator
x={'a':10.1,'b':2,'c':5}
sorted_x = sorted(x.items(), key=operator.itemgetter(1), reversed=True)
out_dict = {}
for idx, (key, _) in enumerate(sorted_x):
    out_dict[key] = idx + 1
print out_dict

【讨论】:

  • OP 不希望它回到字典中吗?
  • 这真的没有意义。字典本身是未排序的,因此将已排序的数据放入未排序的数据结构中对我来说毫无意义。
  • 是的 - 不用于下游。我的猜测是/是它可能用于打印到文件或 JSON 或其他东西。但你的观点很好。 Unsorted => sorted => unsorted 没什么意义。
  • 总体上还不错,但 DSM 的答案可以说更好。您可以使用enumerate(…, 1) 代替idx+1。您还可以轻松地使用字典理解:out_dict = {idx… for }。将原始值保留在 sorted_x 中也有点浪费(有关如何删除它们,请参阅 DSM 的答案)。
【解决方案4】:

一种方法是检查字典中的最大值,然后删除它,同时构建一个新字典:

my_dict = x = {'a':10.1,'b':2,'c':5}
i = 1
new_dict ={}
while len(my_dict) > 0:
    my_biggest_key = max(my_dict, key=my_dict.get)
    new_dict[my_biggest_key] = i
    my_dict.pop(my_biggest_key)
    i += 1
print new_dict

【讨论】:

  • 这个解决方案感觉不像 Python 和笨重。有更优雅的方法可以完成您正在尝试的事情,而无需诉诸 while 语句。
  • 那么,什么。不是拒绝投票的理由。如果它有效,那么它很有用。
  • (我不是最初的反对者)有效的解决方案是有用的,因为它可以解决问题。然而,它甚至可能适得其反,通过展示一种方法或一种风格,如果任何程序员不想浪费 80%他们的时间:DSM 的答案需要两行,所以写起来更快,也更清晰。我认为这样做会适得其反,所以我想劝阻人们不要使用它,否则他们将来会有很多很多问题,代码很长阅读更难理解。
【解决方案5】:
In [23]: from collections import OrderedDict

In [24]: mydict=dict([(j,i) for i, j in enumerate(x.keys(),1)])

In [28]: sorted_dict = sorted(mydict.items(), key=itemgetter(1))

In [29]: sorted_dict
Out[29]: [('a', 1), ('c', 2), ('b', 3)]
In [35]: OrderedDict(sorted_dict)
Out[35]: OrderedDict([('a', 1), ('c', 2), ('b', 3)])

【讨论】:

  • 这不是我答案的近乎完全相同的副本吗?
  • @Zizouz212 你没有使用枚举,你用数字举了一个例子
  • 您的第 28 行是我的答案的准确副本,我对此感到有些奇怪。变量名、方法,一切都一模一样。
  • 这肯定是行不通的,除非有时是偶然的:当你计算mydict时,结果取决于返回x的键的顺序。
  • 同样,它偶然起作用。你的答案是not基于x中的值(x只出现在x.keys()中),这是问题所要求的,所以它不能工作(除非,再次,偶然)。
【解决方案6】:

你可以这样做,

>>> x = {'a':10.1,'b':2,'c':5}
>>> m = {}
>>> k = 0
>>> for i in dict(sorted(x.items(), key=lambda k: k[1], reverse=True)):
        k += 1
        m[i] = k


>>> m
{'a': 1, 'c': 2, 'b': 3}

【讨论】:

  • 这可行,但在许多地方都不必要地复杂(参见 DSM 的答案):(1) 使用变量 k,您正在手动重做 Python 提供的 enumerate。 (2) 不需要显式的int 转换:Python 知道如何直接比较对象。 (3) 你的update 总是写成m[i] = k
【解决方案7】:

相当简单有点简单但有点复杂的单线。

{key[0]:1 + value for value, key in enumerate(
                       sorted(d.iteritems(),
                              key=lambda x: x[1],
                              reverse=True))}

让我带你了解一下。

  • 我们使用enumerate 为我们提供从零开始的元素自然排序。只需使用enumerate(d.iteritems()) 将生成一个包含整数的元组列表,然后生成包含原始字典中键:值对的元组。
  • 我们对列表进行排序,使其按从高到低的顺序显示。
  • 我们希望将该值视为枚举值(也就是说,如果只有一次出现,我们希望 0 成为 'a' 的值(稍后我会对其进行规范化),等等),我们希望键是字典中的实际键。所以在这里,我们交换了绑定两个值的顺序。
  • 在提取实际键时,它仍然是元组形式 - 它显示为 ('a', 0),因此我们只想从中获取第一个元素。 key[0] 做到了。
  • 当我们想要得到实际值时,我们将它的排名归一化,使其从 1 开始而不是从 0 开始,因此我们将 1 加到 value

【讨论】:

  • “鲍勃是第一、第二还是第三?”是一个合理的问题,d["Bob"] == 3 提供了答案。字典没有排序并不意味着 key 和 rank 之间的映射没有用。
  • 这很公平。我会重新考虑一下。
猜你喜欢
  • 1970-01-01
  • 2018-01-02
  • 2014-07-01
  • 2017-01-03
  • 2018-07-08
  • 2011-11-22
  • 2017-12-17
  • 2013-03-20
  • 2020-04-08
相关资源
最近更新 更多