2013-12-24 2 views
3

Мне нужно будет создавать комбинации для двух элементов времени.Комбинации без использования «itertools.combinations»

Если список содержит: seq = ['A', 'B', 'C'] , выход будет ком = [['A', 'B'], ['A', 'C' ], ['B', 'C']]

все это без метода «itertools.combinations».

Я использовал этот код для перестановок. Но как я могу изменить код, чтобы он работал с комбинациями?

def permute(seq): 

    if len(seq) <= 1: 
     perms = [seq] 
    else: 
     perms = [] 
     for i in range(len(seq)): 
      sub = permute(seq[:i]+seq[i+1:]) 
      for p in sub:  
       perms.append(seq[i:i+1]+p) 

return perms 
+2

Почему * без * 'itertools'? – jonrsharpe

+1

Эквивалентный исходный код для 'комбинаций' находится на странице документации' itertools'. Просто скопируйте его в свой файл. – Kevin

+0

Да, я не могу использовать альтернативные методы. Спасибо, я посмотрю. – user3104548

ответ

6

Если вы не хотите использовать itertools, а затем использовать documented pure-Python equivalent:

def combinations(iterable, r): 
    # combinations('ABCD', 2) --> AB AC AD BC BD CD 
    # combinations(range(4), 3) --> 012 013 023 123 
    pool = tuple(iterable) 
    n = len(pool) 
    if r > n: 
     return 
    indices = range(r) 
    yield tuple(pool[i] for i in indices) 
    while True: 
     for i in reversed(range(r)): 
      if indices[i] != i + n - r: 
       break 
     else: 
      return 
     indices[i] += 1 
     for j in range(i+1, r): 
      indices[j] = indices[j-1] + 1 
     yield tuple(pool[i] for i in indices) 
+0

Какова большая сложность этого времени? Я думаю, что это 'O (r * (n!/(R! (N - r)!)))': 'While' циклы' nCr' раз и 'tuple (пул [i] для i в индексах)' делает каждый цикл 'O (r)' работать. Таким образом, это итеративное решение выглядит намного более эффективным, чем [рекурсивное решение обратного отслеживания] (http://www.geeksforgeeks.org/print-all-possible-combinations-of-r-elements-in-a-given-rray-of- size-n /), который я считаю «O (n^r)». – onepiece

+0

Я не сделал анализ сложности; с первого взгляда, я думаю, вы получили сложность правильно. Это, безусловно, значительно ниже O (nr). –

0

Ослабленный перевод рекурсивного кода C++ в answer на аналогичный вопрос:

_NULL = type('_NULL', (object,), {})() # unique sentinel singleton object 

def combinations(sequence, length): 
    """ Find all combinations of the specified length from a sequence. """ 
    if length <= 0: 
     combos = [_NULL] 
    else: 
     combos = [] 
     for i, item in enumerate(sequence, 1): 
      rem_items = sequence[i:] 
      rem_combos = combinations(rem_items, length-1) 
      combos.extend(item if combo is _NULL else [item, combo] 
            for combo in rem_combos) 

    return combos 

print(combinations(['A', 'B', 'C'], 2)) 

Выход:

[['A', 'B'], ['A', 'C'], ['B', 'C']] 
3

Это тривиально сделать непосредственно:

def comb2(s): 
    for i, v1 in enumerate(s): 
     for j in range(i+1, len(s)): 
      yield [v1, s[j]] 

Тогда:

print list(comb2(['A', 'B', 'C'])) 

дисплеи:

[['A', 'B'], ['A', 'C'], ['B', 'C']] 

Единственное, что делает комбинации вообще сложно это питание для known- only-at-runtime Количество элементов, которые нужно брать за раз. Пока вы знаете это число заранее, фиксированное количество циклов вложенных, что глубоко делает работу очевидным образом.

Смежные вопросы