Python中的位置排名和处理关系

Python中的位置排名和处理关系,python,django,math,Python,Django,Math,(很抱歉,此问题的以前版本显示了我需要修复的错误功能,此问题已得到修复,我希望此问题现在更有意义。) 我有一个有分数的对象列表,我正试图根据这些分数为它们分配等级。下面是我输出数据的基本方式 sorted_scores = [ ('Apolo Ohno', 0), ('Shanie Davis', -1), ('Bodie Miller', -2), ('Lindsay Vohn', -3), ('Shawn White', -3), ('Br

(很抱歉,此问题的以前版本显示了我需要修复的错误功能,此问题已得到修复,我希望此问题现在更有意义。)

我有一个有分数的对象列表,我正试图根据这些分数为它们分配等级。下面是我输出数据的基本方式

sorted_scores = [
    ('Apolo Ohno', 0),
    ('Shanie Davis', -1),
    ('Bodie Miller', -2),
    ('Lindsay Vohn', -3),  
    ('Shawn White', -3),
    ('Bryan Veloso', -4)
]
我有一条领带。现在,为上面的对象指定位置的函数是一个简单的for循环,它只指定
i
的值作为对象的最终位置

positions = {}

i = 1
for key, value in sorted_list:
    # Since in my codebase the strings are IDs, I use the key to fetch the object.
    if value is not None:
        positions[key] = i
        i += 1
因此,这显然会返回:

positions = {
    'Apolo Ohno': 1,
    'Shanie Davis': 2,
    'Bodie Miller': 3,
    'Lindsay Vohn': 4,        
    'Shawn White': 5,
    'Bryan Veloso': 6
}
希望这有点道理。问题的核心是这个循环。更有意义的是,如果它像这样返回它们:

positions = {
    'Apolo Ohno': 1,
    'Shanie Davis': 2,
    'Bodie Miller': 3,
    'Lindsay Vohn': 4, # Same value.
    'Shawn White': 4, # Same value.
    'Bryan Veloso': 6
}
我该如何编辑上面的函数才能做到这一点,记住我可以在任何给定的时间拥有任意数量的联系,这取决于我的成员中有多少人对该对象进行了排名?最高排名应该是1,因此可以这样显示:
/


提前感谢。:)

这样做的方法不是计算元素的位置,而是计算有多少其他元素具有更好的分数

编辑:

根据大众的需求,O(n)ed和所有内容:

positions = {}
cur_score = None # Score we're examining
cur_count = 0 # Number of others that we've seen with this score

for ix, (name, score) in enumerate(sorted_scores):
  if score == cur_score: # Same score for this player as previous
    cur_count += 1
  else: # Different score from before
    cur_score = score
    cur_count = 0
  positions[name] = ix - cur_count + 1 # Add 1 because ix is 0-based

print positions

我不得不对你想做什么做一些假设,但这里有一个尝试:

分数={
“lorem”:100,
“ipsum”:200,
“多洛”:300,
"坐":300,,
“amet”:300,
“魁亚”:400,
“奉献者”:500,
“adipising”:500,
"精英":600,,
}
组={}
对于scores.items()中的(成员,分数):
如果不是分组得分:
组[分数]=[成员]
其他:
组[score]。追加(成员)
位置={}
对于枚举(groups.items())中的(秩、(分数、成员)):
对于成员中的成员:
职位[成员]=职级
展开以查看详细信息,以显示工作状态:

导入pprint >>>分数={ …洛勒姆:100, …同侧:200, …多洛:300, …“坐”:300, …艾美特:300, …魁亚:400, …“奉献”:500, .“告别”:500, …“精英”:600, ... } >>>组={} >>>对于scores.items()中的(成员,分数): ... 如果不是分组得分: ... 组[分数]=[成员] ... 其他: ... 组[score]。追加(成员) ... >>>pprint.pprint(组) {100:['lorem'], 200:[“ipsum”], 300:[sit]、[dolor]、[amet], 400:['quia'], 500:['concetetur','adipising'], 600:['elit']} >>>位置={} >>>对于枚举(groups.items())中的(秩、(分数、成员)): ... 对于成员中的成员: ... 职位[成员]=职级 ... >>>pprint.pprint(职位) {'adipsing':4, "艾美特":2,, "奉献":4,, “多洛”:2, "精英":5,, “ipsum”:1, “lorem”:0, "奎亚":3,, '坐':2} >>>pprint.pprint(已排序(positions.items(),key=lambda i:i[1])) [('lorem',0), ('ipsum',1), (‘坐’,2), ('dolor',2), ('amet',2), ('quia',3), ('concetetur',4), ('adipising',4), ('elit',5)]
==规范更改/澄清后的更新===

# coding: ascii

def ranks_from_scores(sorted_scores):
    """sorted_scores: a list of tuples (object_id, score), sorted by score DESCENDING
       return a mapping of object IDs to ranks
    """
    ranks = {}
    previous_score = object()
    for index, (obj_id, score) in enumerate(sorted_scores):
        if score != previous_score:
            previous_score = score
            rank = index + 1
        ranks[obj_id] = rank
    return ranks

from operator import itemgetter
import pprint

scores0 = dict([
    ('Apolo Ohno', 0),
    ('Shanie Davis', -1),
    ('Bodie Miller', -2),
    ('Lindsay Vohn', -3),
    ('Shawn White', -3)
    ])

scores1 = {
    'lorem': 100,
    'ipsum': 200,
    'dolor': 300,
    'sit': 300,
    'amet': 300,
    'quia': 400,
    'consectetur': 500,
    'adipiscing': 500,
    'elit': 600,
    }

scores2 = {
    'lorem': 100,
    'ipsum': 200,
    'dolor': 300,
    'sit': 300,
    'amet': 300,
    'quia': 400,
    'consectetur': 500,
    'adipiscing': 500,
    'elit': 6000,
    }

import pprint
funcs = (ranks_from_scores, ) # Watch this space!
tests = (scores0, scores1, scores2)

for test in tests:
    print
    test_list = sorted(test.items(), key=itemgetter(1), reverse=True)
    print "Input:", test_list
    for func in funcs:
        result = func(test_list)
        print "%s ->" % func.__name__
        pprint.pprint(result)
结果:

Input: [('Apolo Ohno', 0), ('Shanie Davis', -1), ('Bodie Miller', -2), ('Lindsay
 Vohn', -3), ('Shawn White', -3)]
ranks_from_scores ->
{'Apolo Ohno': 1,
 'Bodie Miller': 3,
 'Lindsay Vohn': 4,
 'Shanie Davis': 2,
 'Shawn White': 4}

Input: [('elit', 600), ('consectetur', 500), ('adipiscing', 500), ('quia', 400),
 ('dolor', 300), ('sit', 300), ('amet', 300), ('ipsum', 200), ('lorem', 100)]
ranks_from_scores ->
{'adipiscing': 2,
 'amet': 5,
 'consectetur': 2,
 'dolor': 5,
 'elit': 1,
 'ipsum': 8,
 'lorem': 9,
 'quia': 4,
 'sit': 5}

Input: [('elit', 6000), ('consectetur', 500), ('adipiscing', 500), ('quia', 400)
, ('dolor', 300), ('sit', 300), ('amet', 300), ('ipsum', 200), ('lorem', 100)]
ranks_from_scores ->
{'adipiscing': 2,
 'amet': 5,
 'consectetur': 2,
 'dolor': 5,
 'elit': 1,
 'ipsum': 8,
 'lorem': 9,
 'quia': 4,
 'sit': 5}
==原始提交===

# coding: ascii

def ranks_from_scores(sorted_scores):
    """sorted_scores: a list of tuples (object_id, score), sorted by score DESCENDING
       return a mapping of object IDs to ranks
    """
    ranks = {}
    previous_score = object()
    for index, (obj_id, score) in enumerate(sorted_scores):
        if score != previous_score:
            previous_score = score
            rank = index + 1
        ranks[obj_id] = rank
    return ranks

from operator import itemgetter
import pprint

scores0 = dict([
    ('Apolo Ohno', 0),
    ('Shanie Davis', -1),
    ('Bodie Miller', -2),
    ('Lindsay Vohn', -3),
    ('Shawn White', -3)
    ])

scores1 = {
    'lorem': 100,
    'ipsum': 200,
    'dolor': 300,
    'sit': 300,
    'amet': 300,
    'quia': 400,
    'consectetur': 500,
    'adipiscing': 500,
    'elit': 600,
    }

scores2 = {
    'lorem': 100,
    'ipsum': 200,
    'dolor': 300,
    'sit': 300,
    'amet': 300,
    'quia': 400,
    'consectetur': 500,
    'adipiscing': 500,
    'elit': 6000,
    }

import pprint
funcs = (ranks_from_scores, ) # Watch this space!
tests = (scores0, scores1, scores2)

for test in tests:
    print
    test_list = sorted(test.items(), key=itemgetter(1), reverse=True)
    print "Input:", test_list
    for func in funcs:
        result = func(test_list)
        print "%s ->" % func.__name__
        pprint.pprint(result)
这段代码假设您真的希望最高分数获得排名1,而不是最低分数获得排名1(或0!)

输出:

alist: [(30, 't'), (20, 'w'), (20, 'r'), (20, 'e'), (10, 'q')]
bdict: {'q': 5, 'r': 2, 'e': 2, 't': 1, 'w': 2}
blist: [(1, 't'), (2, 'e'), (2, 'r'), (2, 'w'), (5, 'q')]

看起来您可以使用
sorted
enumerate
内置函数、来自
itertools
groupby
方法和来自
操作符的
itemgetter
方法。假设分数越高越好。。。(如果分数越低越好,将
reverse=True
更改为
reverse=False


下面是一个简单的方法

last = None
position = 0
delta = 1
for key, value in sorted_list:
    if value is not None:
        if value != last:
            position += delta
            delta = 1
        else:
            delta += 1
        # i believe this is supposed to be [key] not [value] in OP's code
        positions[key] = position
        last = value
记住,dicts是无序的,所以要按位置顺序迭代,您需要这样做

>>> print sorted(res.items(),key=itemgetter(1))
[('Apolo Ohno', 1), ('Shanie Davis', 2), ('Bodie Miller', 3), ('Lindsay Vohn', 4), ('Shawn White', 4), ('Bryan Veloso', 6)]
>>> from operator import itemgetter
>>> print sorted(res.items(),key=itemgetter(1))
[('Apolo Ohno', 1), ('Shanie Davis', 2), ('Bodie Miller', 3), ('Lindsay Vohn', 4), ('Shawn White', 4), ('Bryan Veloso', 6)]

解决方案

这里有一种简单的方法,通过稍微修改代码而不是导入模块来实现:

prev = None
rank = 0
incr = 1
positions = {}
for key, value in sorted_list:
    if value is not None:
        if value != prev:
            rank += incr
            incr = 1
        else:
            incr += 1
        positions[key] = rank
        prev = value
测试

为了

我的职位如下:

{'Apolo Ohno': 1, 
'Shanie Davis': 2,
 'Bodie Miller': 3,
 'Lindsay Vohn': 4,
 'Shawn White': 4,
 'Bryan Veloso': 6}
我认为这就是你想要的,即使你不太清楚两个4之后是否应该有一个6

>>> sorted_scores = [
...     ('Apolo Ohno', 0),
...     ('Shanie Davis', -1),
...     ('Bodie Miller', -2),
...     ('Lindsay Vohn', -3),  
...     ('Shawn White', -3),
...     ('Bryan Veloso',-4)
... ]
>>> 
>>> res = {}
>>> prev = None
>>> for i,(k,v) in enumerate(sorted_scores):
...     if v!=prev:
...         place,prev = i+1,v
...     res[k] = place
... 
>>> print res
{'Apolo Ohno': 1, 'Bryan Veloso': 6, 'Shanie Davis': 2, 'Lindsay Vohn': 4, 'Bodie Miller': 3, 'Shawn White': 4}
记住,dicts是无序的,所以要按位置顺序迭代,您需要这样做

>>> print sorted(res.items(),key=itemgetter(1))
[('Apolo Ohno', 1), ('Shanie Davis', 2), ('Bodie Miller', 3), ('Lindsay Vohn', 4), ('Shawn White', 4), ('Bryan Veloso', 6)]
>>> from operator import itemgetter
>>> print sorted(res.items(),key=itemgetter(1))
[('Apolo Ohno', 1), ('Shanie Davis', 2), ('Bodie Miller', 3), ('Lindsay Vohn', 4), ('Shawn White', 4), ('Bryan Veloso', 6)]

这里有一种方法,它将一些其他解决方案的方面结合到一个灵活的生成器函数中

def rank_排序(顺序,开始=1,键=None,反向=True):
“”“枚举迭代器和排序迭代器的组合,用于处理
队伍平平。
"""
previous_value=object()#无法与任何值进行比较
排序的迭代器=排序的(序列,键=键,反转=反转)
对于索引,枚举中的项(排序的迭代器,开始=开始):
#使用键函数选择值(如果给定)
如果键为“无”:
值=项目
其他:
值=键(项)
#仅在排序值更改时更新秩
如果值!=以前的_值:
上一个值=上一个值
排名=指数
产量等级、项目
您可以使用不同的值调用
start
key
reverse
,以允许列组从0或1开始,传递自定义键函数(如
itemgetter(1)
,用于按值对字典排序),并轻松切换到将分数较低的列组视为较高的列组。使用原始问题中的示例:

从操作员导入itemgetter
排序的分数=[
('Apolo Ohno',0),
(‘Shanie Davis’,-1),
('Bodie Miller',-2),
(‘林赛·沃恩’,-3),
(‘肖恩·怀特’,-3),
('Bryan Veloso',-4)
]
越高越好(
(姓名、职级)
排名(姓名、分数)
在排序中(排序的分数,key=itemgetter(1))
)
#{'Apolo Ohno':1,'Bryan Veloso':6,'Shanie Davis':2,'Lindsay Vohn':4,'Bodie Miller':3,'Shawn White':4}
越低越好(
(姓名、职级)
排名(姓名、分数)
在排序中(排序的分数,key=itemgetter(1),reverse=False)
)
#阿波罗
>>> from operator import itemgetter
>>> print sorted(res.items(),key=itemgetter(1))
[('Apolo Ohno', 1), ('Shanie Davis', 2), ('Bodie Miller', 3), ('Lindsay Vohn', 4), ('Shawn White', 4), ('Bryan Veloso', 6)]
    sorted_scores = [
     ('Apolo Ohno', 0),
     ('Shanie Davis', -1),
     ('Bodie Miller', -2),
     ('Lindsay Vohn', -3),  
     ('Shawn White', -3),
     ('Bryan Veloso',-4)
]

res = {}
prev = None
n = 0 
for k,v in sorted_scores:
    if v!=prev:
        n +=1 
        place,prev = n,v
    res[k] = place

print (res)
{'Apolo Ohno': 1, 'Shanie Davis': 2, 'Bodie Miller': 3, 'Lindsay Vohn': 4, 'Shawn White': 4, 'Bryan Veloso': 5}