2016-03-22 59 views
1

我有相同的長度從一堆名單

名單[l1, ..., ln]的列表L我想通過挑選出現的元素比較l1[k], l2[k], ..., ln[k]len(l1)所有k再拍列表l0的採摘最常見的元素最常用。

所以,如果l1 = [1, 2, 3]l2 = [1, 4, 4]l3 = [0, 2, 4],然後l = [1, 2, 4]。如果有平局,我會查看組成領帶的列表,並選擇列表中具有更高優先級的列表。優先事項是先驗的,每個清單都有優先權。例如,如果你有在名單l1l3,並在列表l2l4,並在l5 3,並列出值2值1按照優先級進行排序,說l5>l2>l3>l1>l4,那麼我會選擇2,因爲2是l2包含一個元素的出現次數和優先級高於l1l3

如何在python中做到這一點,而無需創建一個有很多if/else條件的for循環?

+2

你到目前爲止嘗試過什麼?如果可能,請發佈[MCEV](http://stackoverflow.com/help/mcve)。 – Gabriel

+0

@Gabriel我用if/else實現了一個循環,但很快就看起來像個糟糕的主意 – user

+0

如果有領帶怎麼辦?所有的列表都是一樣的長度嗎?你只想比較相同的索引? –

回答

2

解決辦法是:

a = [1, 2, 3] 
b = [1, 4, 4] 
c = [0, 2, 4] 

print [max(set(element), key=element.count) for element in zip(a, b, c)] 
1

試試這個:

l1 = [1,2,3] 
l2 = [1,4,4] 
l3 = [0,2,4] 

lists = [l1, l2, l3] 

print [max(set(x), key=x.count) for x in zip(*lists)] 
2

這就是你要找的內容:

from collections import Counter 
from operator import itemgetter 

l0 = [max(Counter(li).items(), key=itemgetter(1))[0] for li in zip(*l)] 
2

如果你是OK採取一組中的任何一個被綁定爲最常見的元素,並且您可以保證您不會在列表列表中遇到空列表,然後使用Counter(所以,from collections import Counter):

l = [ [1, 0, 2, 3, 4, 7, 8], 
     [2, 0, 2, 1, 0, 7, 1], 
     [2, 0, 1, 4, 0, 1, 8]] 

res = [] 

for k in range(len(l[0])): 
    res.append(Counter(lst[k] for lst in l).most_common()[0][0]) 

在IPython都這樣做,並打印結果:

In [86]: res 
Out[86]: [2, 0, 2, 1, 0, 7, 8] 
3

只需調換子表,並從每個組的Counter.most_common元素鍵:

from collections import Counter 


lists = [[1, 2, 3],[1, 4, 4],[0, 2, 4]] 

print([Counter(sub).most_common(1)[0][0] for sub in zip(*lists)]) 

如果他們是單獨的列表,只需zip那些:

l1, l2, l3 = [1, 2, 3], [1, 4, 4], [0, 2, 4] 

print([Counter(sub).most_common(1)[0][0] for sub in zip(l1,l2,l3)]) 

不知道如何從分組中獲取第一個元素是否合理,因爲它可能不是綁定的那個實例,只是得到兩個most_common並檢查它們的計數是否相等:

def most_cm(lists): 
    for sub in zip(*lists):  
     # get two most frequent 
     comm = Counter(sub).most_common(2) 
     # if their values are equal just return the ele from l1 
     yield comm[0][0] if len(comm) == 1 or comm[0][1] != comm[1][1] else sub[0] 

我們還需要if len(comm) == 1的情況下,所有的元素都是相同的,否則我們會得到一個IndexError。

如果你正在討論的是在領帶事件中採用來自先前列表的元素,即l2在l5之前,那麼這與採取任何配合的元素相同。

對於子列表的一個體面的數量:

In [61]: lis = [[randint(1,10000) for _ in range(10)] for _ in range(100000)] 

In [62]: list(most_cm(lis)) 
Out[62]: [5856, 9104, 1245, 4304, 829, 8214, 9496, 9182, 8233, 7482] 

In [63]: timeit list(most_cm(lis)) 
1 loops, best of 3: 249 ms per loop 
4

您可以使用計數器模塊從集合庫。使用map函數將減少您的列表循環。

import collections 

list0 = [] 
list_length = len(your_lists[0]) 
for k in list_length: 
    k_vals = map(lambda x: x[k], your_lists) #collect all values at k pos 
    counts = collections.Counter(k_vals).most_common() #tuples (val,ct) sorted by count 
    if counts[0][1] > counts[1][1]: #is there a most common value 
     list0.append(counts[0][0]) #takes the value with highest count 
    else: 
     list0.append(k_vals[0]) #takes element from first list 

list0是您正在尋找的答案:沒有最頻繁的價值,但只適用於您將需要一個if/else語句的情況。我只是恨使用l因爲它很容易與數字1

編輯(基於評論)混淆:
結合你的意見,而不是if/else語句,使用while循環:

i = list_length 
while counts[0][1] == counts[1][1]: 
    counts = collections.Counter(k_vals[:i]).most_common() #ignore the lowest priority element 
    i -= 1 #go back farther if there's still a tie 
list0.append(counts[0][0]) #takes the value with highest count once there's no tie 

所以整個事情現在是:

import collections 

list0 = [] 
list_length = len(your_lists[0]) 
for k in list_length: 
    k_vals = map(lambda x: x[k], your_lists) #collect all values at k pos 
    counts = collections.Counter(k_vals).most_common() #tuples (val,ct) sorted by count 
    i = list_length 
    while counts[0][1] == counts[1][1]: #in case of a tie 
     counts = collections.Counter(k_vals[:i]).most_common() #ignore the lowest priority element 
     i -= 1 #go back farther if there's still a tie 
    list0.append(counts[0][0]) #takes the value with highest count 

你扔在一個更細小的循環,但光明的一面沒有的if/else狀態簡直就是!

+2

我認爲它可能會崩潰,如果所有值是相同的,因爲不會有一個計數[1] [1] – user

+0

與拉姆達的地圖也會比拉鍊慢 –