2013-01-11 73 views
3

接聽一個Question名單,我結束了,我認爲很可能已經在一個更好的辦法是做解決的迂迴方式有問題,但我是一無所知,排序基於給定的分佈

有兩個列表

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

optimal_partition,是數字8的整數劃分的一成4份

我想排序optimal_partition,其中,所述百分比分佈相匹配爲最接近儘可能瓦特的方式HICH將意味着,個別分區應符合%的幅度作爲最接近地

所以3 -> 0.42 -> 0.270.231 -> 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] 
+1

定義 – Woot4Moo

+0

@ Woot4Moo 「來解決這個更簡單的方式」:單個排序基於鍵而不是多個排序和存儲和像我的例子 – Abhijit

回答

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) 
+0

那樣檢索索引,這比我的方法簡單得多。 –

+0

看起來很有趣。我必須先嚐試一下,然後才能回覆 – Abhijit

+0

不幸的是,在zip和'numpy'的情況下,第三個例子似乎有點偏離軌道。實際上'3'應該映射到0.4這個最高的pct分佈。我認爲你的'numpy'解決方案非常優雅,但是我們都缺少一些明顯的東西。在超越之前,我會用你的'numpy'解決方案做一點工作。 – Abhijit

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 

現在,我不知道我會說這「更容易」。我沒有對它進行測試,並且我確信在最後一節中我弄錯了邏輯。事實上,我試圖分配給元組,所以我知道至少有一個錯誤。但這是一種不同的方法。