根据给定的分布对列表进行排序

时间:2013-01-11 19:12:01

标签: python sorting

回答一个Question,我最终遇到了一个问题,我认为这是一种解决问题的方法,可以用更好的方式完成,但我一无所知

有两个列表

percent = [0.23, 0.27, 0.4, 0.1]
optimal_partition = [3, 2, 2, 1]

optimal_partition,是数字8到4个部分的整数分区之一

我想按照与百分比分布相匹配的方式对optimal_partition进行排序,以尽可能接近,这意味着,单个分区应尽可能匹配最接近的百分比

所以3 -> 0.42 -> 0.270.23以及1 -> 0.1

所以最后的结果应该是

[2, 2, 3, 1]

我最终解决这个问题的方式是

>>> percent = [0.23, 0.27, 0.4, 0.1]
>>> optimal_partition = [3, 2, 2, 1]
>>> optimal_partition_percent = zip(sorted(optimal_partition),
                    sorted(enumerate(percent),
                       key = itemgetter(1)))
>>> optimal_partition = [e for e, _ in sorted(optimal_partition_percent,
                          key = lambda e: e[1][0])]
>>> optimal_partition
[2, 2, 3, 1]

您能建议一种更简单的方法来解决这个问题吗?

我的意思是,更简单,无需实现多重排序,并根据索引进行存储和后续重新排列。

更多例子:

percent = [0.25, 0.25, 0.4, 0.1]
optimal_partition = [3, 2, 2, 1]
result = [2, 2, 3, 1]

percent = [0.2, 0.2, 0.4, 0.2]
optimal_partition = [3, 2, 2, 1]
result = [1, 2, 3, 2]

2 个答案:

答案 0 :(得分:3)

from numpy import take,argsort

take(opt,argsort(argsort(perc)[::-1]))

或没有导入:

zip(*sorted(zip(sorted(range(len(perc)), key=perc.__getitem__)[::-1],opt)))[1]

#Test

l=[([0.23, 0.27, 0.4, 0.1],[3, 2, 2, 1]),
   ([0.25, 0.25, 0.4, 0.1],[3, 2, 2, 1]),
   ([0.2,  0.2,  0.4, 0.2],[3, 2, 2, 1])]

def f1(perc,opt):
    return take(opt,argsort(argsort(perc)[::-1]))

def f2(perc,opt):
    return zip(*sorted(zip(sorted(range(len(perc)),
             key=perc.__getitem__)[::-1],opt)))[1]       

for i in l:
    perc, opt = i
    print f1(perc,opt), f2(perc,opt)

# output:
# [2 2 3 1] (2, 2, 3, 1)
# [2 2 3 1] (2, 2, 3, 1)
# [1 2 3 2] (1, 2, 3, 2)

答案 1 :(得分:0)

使用百分比总和为1:

的事实
percent = [0.23, 0.27, 0.4, 0.1]
optimal_partition = [3, 2, 2, 1]
total = sum(optimal_partition)
output = [total*i for i in percent]

现在你需要想办法以某种方式重新分配小数分量。大声思考:

from operator import itemgetter
intermediate = [(i[0], int(i[1]), i[1] - int(i[1])) for i in enumerate(output)]
# Sort the list by the fractional component
s = sorted(intermediate, key=itemgetter(2))
# Now, distribute the first item's fractional component to the rest, starting at the top:
for i, tup in enumerate(s):
    fraction = tup[2]
    # Go through the remaining items in reverse order
    for index in range(len(s)-1, i, -1):
        this_fraction = s[index][2]
        if fraction + this_fraction >= 1:
            # increment this item by 1, clear the fraction, carry the remainder
            new_fraction = fraction + this_fraction -1
            s[index][1] = s[index][1] + 1
            s[index][2] = 0
            fraction = new_fraction
        else:
            #just add the fraction to this element, clear the original element
            s[index][2] = s[index][2] + fraction

现在,我不确定我会说“更容易”。我没有对它进行过测试,我确信在上一节中我的逻辑错误了。事实上,我正在尝试分配元组,所以我知道至少有一个错误。但这是一种不同的方法。