Набор перестановок логического массива длины n
с точно m
истинными значениями, по сути, совпадает с набором m
-комбинаций из набора n
вещей, что и является возвращается itertools.combinations
. (В данном случае n
- это индексы истинных значений m
.)
Чтобы получить перестановки от до m
истинных значений, нам просто нужно связать воедино комбинации значений i
для i
в range(m + 1)
, что можно легко сделать с помощью itertools.chain.from_iterable
from itertools import combinations, chain
# This returns an iterator
up_to_m_of_n = lambda n, m: chain.from_iterable(combinations(range(n), i)
for i in range(m+1))
# Example:
list(up_to_m_of_n(4, 2))
[(), (0,), (1,), (2,), (3,), (0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)]
Превращение этих индексных массивов в логический массив немного раздражает, но все же выполнимо:
from operator import setitem
from functools import reduce
up_to_m_of_n_true = lambda n, m: map(lambda inds: reduce(lambda a, ind: setitem(a, ind, True) or a,
inds, [False] * n),
up_to_m_of_n(n, m))
# Example (output reformatted)
list(up_to_m_of_n_true(4,2))
[False, False, False, False]
[True, False, False, False]
[False, True, False, False]
[False, False, True, False]
[False, False, False, True]
[True, True, False, False]
[True, False, True, False]
[True, False, False, True]
[False, True, True, False]
[False, True, False, True]
[False, False, True, True]
Обратите внимание, что в отличие от вашего примера, это относится и к случаю, когда значения True отсутствуют.
Возможно, чрезмерно функциональный up_to_m_of_n_true может быть более читабельным, как:
def indices_to_boolean(n, inds):
bools = [False] * n
for ind in inds: bools[ind] = True
return bools
def up_to_m_of_n_true(n, m):
for inds in up_to_m_of_n(n, m):
yield indices_to_boolean(inds, n)