2012-04-12 53 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