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}