You want the product of all the lists. To include the case where you select zero elements from any given list, you can add None to all the lists, and then remove None elements before you yield a selection.
This assumes you don't have any Nones in the original lists. If you do, you can replace the Nones in this logic with some dummy value that your lists won't contain.
import itertools
def optional_product(*iterables, dummy=None):
iterables = [itertools.chain(itbl, [dummy]) for itbl in iterables]
for selection in itertools.product(*iterables):
sel = [s for s in selection if s != dummy]
yield sel
Note: To support iterables other than lists, I use itertools.chain to "append" a None to each input iterable.
To run this:
for sel in optional_product([2], [2,3], [4], [1,2], [2], [1,4]):
print(sel)
which prints:
[2, 2, 4, 1, 2, 1]
[2, 2, 4, 1, 2, 4]
[2, 2, 4, 1, 2]
[2, 2, 4, 1, 1]
[2, 2, 4, 1, 4]
[2, 2, 4, 1]
[2, 2, 4, 2, 2, 1]
[2, 2, 4, 2, 2, 4]
[2, 2, 4, 2, 2]
[2, 2, 4, 2, 1]
[2, 2, 4, 2, 4]
[2, 2, 4, 2]
[2, 2, 4, 2, 1]
[2, 2, 4, 2, 4]
[2, 2, 4, 2]
[2, 2, 4, 1]
[2, 2, 4, 4]
[2, 2, 4]
[2, 2, 1, 2, 1]
[2, 2, 1, 2, 4]
[2, 2, 1, 2]
[2, 2, 1, 1]
[2, 2, 1, 4]
[2, 2, 1]
[2, 2, 2, 2, 1]
[2, 2, 2, 2, 4]
[2, 2, 2, 2]
[2, 2, 2, 1]
[2, 2, 2, 4]
[2, 2, 2]
[2, 2, 2, 1]
[2, 2, 2, 4]
[2, 2, 2]
[2, 2, 1]
[2, 2, 4]
[2, 2]
[2, 3, 4, 1, 2, 1]
[2, 3, 4, 1, 2, 4]
[2, 3, 4, 1, 2]
[2, 3, 4, 1, 1]
[2, 3, 4, 1, 4]
[2, 3, 4, 1]
[2, 3, 4, 2, 2, 1]
[2, 3, 4, 2, 2, 4]
[2, 3, 4, 2, 2]
[2, 3, 4, 2, 1]
[2, 3, 4, 2, 4]
[2, 3, 4, 2]
[2, 3, 4, 2, 1]
[2, 3, 4, 2, 4]
[2, 3, 4, 2]
[2, 3, 4, 1]
[2, 3, 4, 4]
[2, 3, 4]
[2, 3, 1, 2, 1]
[2, 3, 1, 2, 4]
[2, 3, 1, 2]
[2, 3, 1, 1]
[2, 3, 1, 4]
[2, 3, 1]
[2, 3, 2, 2, 1]
[2, 3, 2, 2, 4]
[2, 3, 2, 2]
[2, 3, 2, 1]
[2, 3, 2, 4]
[2, 3, 2]
[2, 3, 2, 1]
[2, 3, 2, 4]
[2, 3, 2]
[2, 3, 1]
[2, 3, 4]
[2, 3]
[2, 4, 1, 2, 1]
[2, 4, 1, 2, 4]
[2, 4, 1, 2]
[2, 4, 1, 1]
[2, 4, 1, 4]
[2, 4, 1]
[2, 4, 2, 2, 1]
[2, 4, 2, 2, 4]
[2, 4, 2, 2]
[2, 4, 2, 1]
[2, 4, 2, 4]
[2, 4, 2]
[2, 4, 2, 1]
[2, 4, 2, 4]
[2, 4, 2]
[2, 4, 1]
[2, 4, 4]
[2, 4]
[2, 1, 2, 1]
[2, 1, 2, 4]
[2, 1, 2]
[2, 1, 1]
[2, 1, 4]
[2, 1]
[2, 2, 2, 1]
[2, 2, 2, 4]
[2, 2, 2]
[2, 2, 1]
[2, 2, 4]
[2, 2]
[2, 2, 1]
[2, 2, 4]
[2, 2]
[2, 1]
[2, 4]
[2]
[2, 4, 1, 2, 1]
[2, 4, 1, 2, 4]
[2, 4, 1, 2]
[2, 4, 1, 1]
[2, 4, 1, 4]
[2, 4, 1]
[2, 4, 2, 2, 1]
[2, 4, 2, 2, 4]
[2, 4, 2, 2]
[2, 4, 2, 1]
[2, 4, 2, 4]
[2, 4, 2]
[2, 4, 2, 1]
[2, 4, 2, 4]
[2, 4, 2]
[2, 4, 1]
[2, 4, 4]
[2, 4]
[2, 1, 2, 1]
[2, 1, 2, 4]
[2, 1, 2]
[2, 1, 1]
[2, 1, 4]
[2, 1]
[2, 2, 2, 1]
[2, 2, 2, 4]
[2, 2, 2]
[2, 2, 1]
[2, 2, 4]
[2, 2]
[2, 2, 1]
[2, 2, 4]
[2, 2]
[2, 1]
[2, 4]
[2]
[3, 4, 1, 2, 1]
[3, 4, 1, 2, 4]
[3, 4, 1, 2]
[3, 4, 1, 1]
[3, 4, 1, 4]
[3, 4, 1]
[3, 4, 2, 2, 1]
[3, 4, 2, 2, 4]
[3, 4, 2, 2]
[3, 4, 2, 1]
[3, 4, 2, 4]
[3, 4, 2]
[3, 4, 2, 1]
[3, 4, 2, 4]
[3, 4, 2]
[3, 4, 1]
[3, 4, 4]
[3, 4]
[3, 1, 2, 1]
[3, 1, 2, 4]
[3, 1, 2]
[3, 1, 1]
[3, 1, 4]
[3, 1]
[3, 2, 2, 1]
[3, 2, 2, 4]
[3, 2, 2]
[3, 2, 1]
[3, 2, 4]
[3, 2]
[3, 2, 1]
[3, 2, 4]
[3, 2]
[3, 1]
[3, 4]
[3]
[4, 1, 2, 1]
[4, 1, 2, 4]
[4, 1, 2]
[4, 1, 1]
[4, 1, 4]
[4, 1]
[4, 2, 2, 1]
[4, 2, 2, 4]
[4, 2, 2]
[4, 2, 1]
[4, 2, 4]
[4, 2]
[4, 2, 1]
[4, 2, 4]
[4, 2]
[4, 1]
[4, 4]
[4]
[1, 2, 1]
[1, 2, 4]
[1, 2]
[1, 1]
[1, 4]
[1]
[2, 2, 1]
[2, 2, 4]
[2, 2]
[2, 1]
[2, 4]
[2]
[2, 1]
[2, 4]
[2]
[1]
[4]
[]
The last value yielded is the case where zero elements are selected from all lists. If you don't want this, you can simply yield sel only when sel is non-empty.
To obtain a list of lists containing all selections, just do list(optional_product(...))