我有按降序排序的元素树列表。我需要做的是使用Borda’s positional ranking来组合排名列表,使用每个列表中元素的序数等级的信息。给每个候选c和列表ti列出t1,t2,t3 ... tk,得分B ti(c)是在ti中排在c以下的候选者的数量。 所以Borda总分为B(c)=ΣBti(c) 然后候选人按降序Borda分数排序。
我把它捆绑了,但它没有提供所需的输出:
for i in list1, list2, list3:
borda = (((len(list1)-1) - list1.index(i)) + ((len(list2)-1) - list2.index(i)) + ((len(list3)-1) - list3.index(i)))
print borda
有人可以帮我实现上述功能吗?
答案 0 :(得分:1)
调用索引(i)需要与列表大小成比例的时间,并且因为你必须为每个元素调用它,所以它最终需要O(N ^ 2)时间,其中N是列表大小。最好在你知道索引的时候迭代一个列表,并将得分的那一部分添加到dict中的得分累加器。
def borda_sort(lists):
scores = {}
for l in lists:
for idx, elem in enumerate(reversed(l)):
if not elem in scores:
scores[elem] = 0
scores[elem] += idx
return sorted(scores.keys(), key=lambda elem: scores[elem], reverse=True)
lists = [ ['a', 'c'], ['b', 'd', 'a'], ['b', 'a', 'c', 'd'] ]
print borda_sort(lists)
# ['b', 'a', 'c', 'd']
这里唯一棘手的部分是反向扫描列表;这可以确保如果一个元素根本不在其中一个列表中,那么该列表的分数会增加0。
与其他建议比较:
import itertools
import random
def borda_simple_sort(lists):
candidates = set(itertools.chain(*lists))
return sorted([sum([len(l) - l.index(c) - 1 for l in lists if c in l], 0) for c in candidates], reverse=True)
# returns scores - a bit more work needed to return a list
# make 10 random lists of size 10000
lists = [ random.sample(range(10000), 10000) for x in range(10) ]
%timeit borda_sort(lists)
10 loops, best of 3: 40.9 ms per loop
%timeit borda_simple_sort(lists)
1 loops, best of 3: 30.8 s per loop
这不是一个错字:) 40 milli 秒对30秒,750x加速。在这种情况下,快速算法读取起来并不困难,甚至可能更容易阅读,它只依赖于适当的辅助数据结构,并以正确的顺序遍历数据。
答案 1 :(得分:0)
这可行:
sorted([sum([len(l) - l.index(c) - 1 for l in [list1, list2, list3] if c in l], 0) for c in [candidate1, candidate2, candidate3]], reverse=True)
请注意,由于分数会重新排序,因此您将忘记每个分数属于哪个候选人:
>>> list1 = ['a', 'c']
>>> list2 = ['b', 'd', 'a']
>>> list3 = ['b', 'a', 'c', 'd']
>>> candidates = ['a', 'b', 'c', 'd']
>>> sorted([sum([len(l) - l.index(c) - 1 for l in [list1, list2, list3] if c in l], 0) for c in candidates], reverse=True)
[5, 3, 1, 1]
在这种情况下,列表的第一个元素(获胜者)是'b',是候选人列表中的第二个元素。