2013-11-02 1 views
4

Как я могу пропустить кортежи, которые имеют повторяющиеся элементы на итерации, когда я использую itertools.product? Или, допустим, есть ли вообще не смотреть на них на итерации? Поскольку пропуски могут занять много времени, если количество списков слишком велико.itertools.product, устраняющий повторяющиеся элементы

Example, 
lis1 = [1,2] 
lis2 = [2,4] 
lis3 = [5,6] 

[i for i in product(lis1,lis2,lis3)] should be [(1,2,5), (1,2,6), (1,4,5), (1,4,6), (2,4,5), (2,4,6)] 

Это не будет (2,2,5) и (2,2,6), так как 2 является продублировать здесь. Как я могу это сделать?

ответ

10

itertools обычно работает на уникальных позиций в входов, а не на уникальных значений. Поэтому, когда вы хотите удалить повторяющиеся значения, вам обычно приходится либо обрабатывать последовательность результатов itertools, либо «сворачивать свои собственные». Потому что после обработки может быть очень неэффективным в этом случае свернуть свой собственный:

def uprod(*seqs): 
    def inner(i): 
     if i == n: 
      yield tuple(result) 
      return 
     for elt in sets[i] - seen: 
      seen.add(elt) 
      result[i] = elt 
      for t in inner(i+1): 
       yield t 
      seen.remove(elt) 

    sets = [set(seq) for seq in seqs] 
    n = len(sets) 
    seen = set() 
    result = [None] * n 
    for t in inner(0): 
     yield t 

Тогда, например,

>>> print list(uprod([1, 2, 1], [2, 4, 4], [5, 6, 5])) 
[(1, 2, 5), (1, 2, 6), (1, 4, 5), (1, 4, 6), (2, 4, 5), (2, 4, 6)] 
>>> print list(uprod([1], [1, 2], [1, 2, 4], [1, 5, 6])) 
[(1, 2, 4, 5), (1, 2, 4, 6)] 
>>> print list(uprod([1], [1, 2, 4], [1, 5, 6], [1])) 
[] 
>>> print list(uprod([1, 2], [3, 4])) 
[(1, 3), (1, 4), (2, 3), (2, 4)] 

Это может быть гораздо более эффективным, так как дублирует значение никогда даже не рассматривается (ни внутри входного итерабельного, ни через них).

+0

Почему это не работает Тим ​​?: 'В [77]: список (uprod ([0, 1], [0, 1], [2, 3, 0, 4, 5, 6, 1], [0, 5], [7, 0, 5], [7, 0, 5], [7, 6, 0, 8, 5], [7, 6, 0, 8, 5], [7, 8, 5] , [7, 8, 5])) Out [77]: [] ' – Handloomweaver

+0

Результат выглядит корректно для меня: передайте те же последовательности в' itertools.product() ', и по крайней мере один дубликат в каждом из 113400 выход 10 кортежей. Что вы должны делать? –

+0

Я просто получаю пустой список на Python 2.7.12 для 'list (uprod ([0, 1], [0, 1], [2, 3, 0, 4, 5, 6, 1], [ 0, 5], [7, 0, 5], [7, 0, 5], [7, 6, 0, 8, 5], [7, 6, 0, 8, 5], [7, 8, 5], [7, 8, 5])) 'Вы не понимаете этого? – Handloomweaver

5
lis1 = [1,2] 
lis2 = [2,4] 
lis3 = [5,6] 
from itertools import product 
print [i for i in product(lis1,lis2,lis3) if len(set(i)) == 3] 

Выход

[(1, 2, 5), (1, 2, 6), (1, 4, 5), (1, 4, 6), (2, 4, 5), (2, 4, 6)] 
+0

Почему downvote? – thefourtheye

+0

Это решение, но, как я сказал в проблеме, этот метод неэффективен. Предположим, что у вас есть 30 списков внутри lis, а первые два списка - [1,0], [1,2]. Он не мог найти какое-либо решение, если это не сделано с частью (1,1, ....). Это очень трудоемко. – genclik27

+0

@ genclik27 Не могли бы вы дать мне образцы данных, для которых это не сработает? – thefourtheye

0

С itertools.combinations не будет никаких повторяющихся элементов в отсортированном порядке:

>>> lis = [1, 2, 4, 5, 6] 
>>> list(itertools.combinations(lis, 3)) 
[(1, 2, 4), (1, 2, 5), (1, 2, 6), (1, 4, 5), (1, 4, 6), (1, 5, 6), (2, 4, 5), 
(2, 4, 6), (2, 5, 6), (4, 5, 6)]