2012-04-12 49 views
2

使用列表理解,itertools或類似函數,是否可以根據條件創建兩個不等列表?下面是一個例子:Python列表理解從列表中使用條件創建不等長列表

main_list = [6, 3, 4, 0, 9, 1] 
part_list = [4, 5, 1, 2, 7] 

in_main = [] 
out_main = [] 

for p in part_list: 
    if p not in main_list: 
    out_main.append(p) 
    else: 
    in_main.append(p) 

print out_main 
print in_main 

>>> [5, 2, 7] 
>>> [4, 1] 

試圖保持它的簡單,但作爲使用的一個例子,main_list可以是從用含有字典鍵part_list的字典值。需要同時生成兩個列表。心連心。

+3

我覺得這可以用集合來完成 – 2012-04-12 13:48:25

+0

@JakobBowyer main_list值可以從字典中生成。集合是顯而易見的解決方案,但尋找一個列表理解或itertools類型的解決方案,同時生成兩個列表。 – 2012-04-12 14:02:59

回答

2

真正itertools爲基礎的解決方案,在一個迭代的工作原理:

>>> part_iter = iter(part_list) 
>>> part_in, part_out = itertools.tee(part_iter) 
>>> in_main = (p for p in part_in if p in main_list) 
>>> out_main = (p for p in part_out if p not in main_list) 

使羅列出這些失敗的使用迭代器的點,但這裏是結果:

>>> list(in_main) 
[4, 1] 
>>> list(out_main) 
[5, 2, 7] 

這具有從另一個懶惰生成的序列中懶惰地生成in_mainout_main的優點。唯一的問題是,如果你先迭代一個,那麼tee必須緩存一堆數據,直到它被其他迭代器使用。所以這隻有在大致同時迭代它們時纔有用。否則,你可能會自己使用輔助存儲。

還有一個有趣的基於三元運算符的解決方案。 (你可以把它壓縮到一個列表理解中,但這是錯誤的。)我將main_list改爲O(1)查找的集合。

>>> main_set = set(main_list) 
>>> in_main = [] 
>>> out_main = [] 
>>> for p in part_list: 
...  (in_main if p in main_set else out_main).append(p) 
... 
>>> in_main 
[4, 1] 
>>> out_main 
[5, 2, 7] 

還有一個有趣的collections.defaultdict方法:

>>> import collections 
>>> in_out = collections.defaultdict(list) 
>>> for p in part_list: 
...  in_out[p in main_list].append(p) 
... 
>>> in_out 
defaultdict(<type 'list'>, {False: [5, 2, 7], True: [4, 1]}) 
+0

+1第二個解決你的名字。 – jamylak 2012-04-12 14:35:11

+0

@jamylak,不知道爲什麼? – senderle 2012-04-12 14:37:36

+0

似乎它已經過度使用它,它也會涉及到壓縮最終結果並從'in_main'和'out_main'中過濾'None'。 – jamylak 2012-04-12 14:40:14

5

IF(內part_list)的順序很重要:

out_main = [p for p in part_list if p not in main_list] 
in_main = [p for p in part_list if p in main_list] 

否則:

out_main = list(set(part_list) - set(main_list)) 
in_main = list(set(part_list) & set(main_list)) 
+0

我發誓我先寫了答案的答案:P – 2012-04-12 13:53:15

+0

看到有問題的評論。 – 2012-04-12 14:03:56

6

只要你有沒有重複的數據&順序並不重要。

main_set = set([6, 3, 4, 0, 9, 1]) 
part_set = set([4, 5, 1, 2, 7]) 

out_main = part_set - main_set 
in_main = part_set & main_set 

工作完成。

+3

只要順序無關緊要。 – huon 2012-04-12 13:51:13

+0

更新我的答案,以反映您點 – 2012-04-12 13:54:29

+0

變量希望被命名爲'main_set'和'part_set' :( – 0xc0de 2012-04-12 13:58:25

0
in_main = list(set(main_list) & set(part_list)) 
out_main = list(set(part_list) - set(in_main)) 
0

開始由謂詞的列表:

test_func = [part_list.__contains__, lambda x: not part_list.__contains__(x)] 
# Basically, each of the predicates is a function that returns a True/False value  
# (or similar) according to a certain condition. 
# Here, you wanted to test set intersection; but you could have more predicates. 

print [filter(func, main_list) for func in test_func] 

然後你有你的「一個班輪」,但你有一點通過維護一個謂詞列表的開銷工作

正如在其他答案中說的,你可以加快查找b y使用set(main_list)代替(不在列表理解當然,但在之前)。

+0

我更喜歡downvotes,但你只是想解釋爲什麼?謝謝! – 2012-04-12 14:59:14

+0

我贊成你,因爲我討厭人們在沒有反饋的情況下倒退。 – Danny 2012-10-09 21:15:19

+1

非常感謝! – 2012-10-09 21:43:19