独特产品与itertools的组合

时间:2018-11-20 15:52:27

标签: python list permutation itertools

我有一个嵌套列表,想将两个项目制成乘积。

test = [[('juice', 'NOUN'), ('orange', 'FLAVOR')], 
        [('juice', 'NOUN'), ('orange', 'FLAVOR'), ('lemon', 'FLAVOR')],
        [('orange', 'FLAVOR'), ('chip', 'NOUN')]]

我期望的是这样的:

[(('juice', 'NOUN'), ('lemon', 'FLAVOR')), 
 (('juice', 'NOUN'), ('chip', 'NOUN')),
 (('orange', 'FLAVOR'), ('lemon', 'FLAVOR')),
 (('orange', 'FLAVOR'), ('chip', 'NOUN')),
 (('lemon', 'FLAVOR'), ('chip', 'NOUN'))]

这就是说,我想跨列表进行排列,但仅针对唯一项。我更喜欢使用itertools。以前,我尝试过list(itertools.product(*test)),但是我意识到它将产生嵌套列表长度的乘积...

我当前的代码:

unique_list = list(set(itertools.chain(*test)))
list(itertools.combinations(unique_list, 2))

我的想法是首先获取嵌套列表中的唯一项,因此嵌套列表将为[[('juice', 'NOUN'), ('orange', 'FLAVOR')], [('lemon', 'FLAVOR')], [('chip', 'NOUN')]],然后使用itertools.combinations进行置换。但是,它会在列表中排列(即果汁和橙子一起出现),这是我不希望出现在结果中的。

1 个答案:

答案 0 :(得分:1)

这可以满足您的要求,无需将原始列表的大小固定为3:

输入:

test = [[('juice', 'NOUN'), ('orange', 'FLAVOR')], 
        [('juice', 'NOUN'), ('orange', 'FLAVOR'), ('lemon', 'FLAVOR')],
        [('juice', 'NOUN'), ('chip', 'NOUN')]]

首先,重新格式化输入以删除重复项(请参见注释1):

test = [[x for x in sublist if x not in sum(test[:i], [])] for i, sublist in enumerate(test)]

最后,获取product中的combinations

from itertools import combinations, product

for c in combinations(test, 2):
    for x in product(*c):
        print(x)

产生:

(('juice', 'NOUN'), ('lemon', 'FLAVOR'))
(('orange', 'FLAVOR'), ('lemon', 'FLAVOR'))
(('juice', 'NOUN'), ('chip', 'NOUN'))
(('orange', 'FLAVOR'), ('chip', 'NOUN'))
(('lemon', 'FLAVOR'), ('chip', 'NOUN'))

  1. 删除内部元组(如果在以前的任何子列表中都可见)。 sum(test[:i], [])的神奇之处在于将所有先前的子列表“相加”在一起,仅执行一次成员资格检查。

对于紧凑性和样式点,还有上述的列表理解版本:

res = [x for c in combinations(test, 2) for x in product(*c)]