Модуль itertools
действительно возвращает генераторы вместо списков, но:
- Генераторы часто более эффективны, чем списки (особенно если вы генерируете большое количество комбинаций)
- Вы всегда можете преобразовать генераторы в списки, используя
list(...)
, когда вам действительно нужно.
chain
и combinations
функции itertools
работают хорошо , но вам нужно использовать Python 2.6 или более поздней версии:
import itertools
def all_combinations(any_list):
return itertools.chain.from_iterable(
itertools.combinations(any_list, i + 1)
for i in xrange(len(any_list)))
Затем вы можете назвать это так:
# as a generator
all_combinations([1,2,3]) # --> <itertools.chain at 0x10ef7ce10>
# as a list
list(all_combinations([1,2,3])) # --> [(1,), (2,), (3,), (1, 2), (1, 3), (2, 3), (1, 2, 3)]
# as a list of lists
[list(l) for l in all_combinations([1,2,3])] # --> [[1], [2], [3], [1, 2], [1, 3], [2, 3], [1, 2, 3]]
Если вы ранее не использовали генераторы, обратите внимание, что вы просматриваете их, как если бы они были списком, например:
# a generator returned instead of list
my_combinations = all_combinations([1,2,3])
# this would also work if `my_combinations` were a list
for c in my_combinations:
print "Combo", c
"""
Prints:
Combo (1,)
Combo (2,)
Combo (3,)
Combo (1, 2)
Combo (1, 3)
Combo (2, 3)
Combo (1, 2, 3)
"""
Разница в производительности может быть существенной. Если вы сравните производительность, вы увидите, что генератор гораздо быстрее создать:
# as a generator
all_combinations(range(25)) # timing: 100000 loops, best of 3: 2.53 µs per loop
# as a list
list(all_combinations(range(25))) # timing: 1 loops, best of 3: 9.37 s per loop
Обратите внимание, что в любом случае для перебора всех комбинаций потребуется некоторое время, но это может бытьбольшая победа для вас, особенно если вы найдете то, что ищете Эрлу вкл.