Генерация всех перестановок с отдельными ограничениями для каждого индекса

1

Скажем, у нас есть список, например, [3, 2, 1]. Я хотел бы сгенерировать все перестановки этого списка в форме:

[1, 1, 1], [2, 1, 1], [3, 1, 1], [1, 2, 1], [2, 2, 1] , [3, 2, 1]

для любого списка длины n. Таким образом, значение i го элемента исходного списка является верхним пределом для значения i го элемента всех перестановок.

Я также хотел бы использовать генератор, используя yield, так как список ввода может быть довольно большим (например, n = 30).

До сих пор я использовал что-то вроде этого:

itertools.product(range(1, 5), repeat=5)

Который имеет следующий выход при использовании в цикле for:

(1, 1, 1, 1, 1), (1, 1, 1, 1, 2), (1, 1, 1, 1, 3), (1, 1, 1, 1, 4), (1, 1, 1, 2, 1), (1, 1, 1, 2, 2), (1, 1, 1, 2, 3), ... 

Однако я не думаю, что он позволяет указать пользовательские лимиты для каждого элемента перестановок.

Также обратите внимание, что элементы входного списка необязательно должны быть последовательными числами, поэтому [25, 17, 10, 4] является допустимым вводом.

  • 0
    Почему [3,3,3] возможности?
  • 0
    @RafaelC Поскольку вторым элементом является 2, второй элемент всех перестановок должен быть меньше или равен 2. Я отредактировал вопрос, чтобы прояснить это.
Показать ещё 2 комментария
Теги:
list
generator
permutation

3 ответа

1
Лучший ответ

Эта рекурсивная функция возвращает генератор в желаемом порядке:

def f(limits):
    if not limits:
        yield ()
        return

    for l in f(limits[1:]):
        for i in range(1, limits[0]+1):
            yield (i,) + l

>>> print(list(f([3, 2, 1])))
[(1, 1, 1), (2, 1, 1), (3, 1, 1), (1, 2, 1), (2, 2, 1), (3, 2, 1)]
1

Вы можете фильтровать результаты itertools.product

>>> from itertools import product
>>> l = [3,2,1]
>>> list(filter(lambda t: all(x<=y for x,y in zip(t,l)), product(l, repeat=len(l))))
[(3, 2, 1), (3, 1, 1), (2, 2, 1), (2, 1, 1), (1, 2, 1), (1, 1, 1)]
  • 0
    Не могли бы вы указать , какие l в примере?
  • 1
    @aL_eX Извините .. Обновлено
Показать ещё 3 комментария
0

Вы ищете декартово произведение множества диапазонов, аргумент которых определяется вашим входным списком:

from itertools import product
lims = [3, 2, 1]
gen = product(*(range(1,lim+1) for lim in lims))
print(list(gen))

В результате

[(1, 1, 1), (1, 2, 1), (2, 1, 1), (2, 2, 1), (3, 1, 1), (3, 2, 1)]

Ещё вопросы

Сообщество Overcoder
Наверх
Меню