Search code examples
pythonpython-3.xiteratorgeneratorpython-itertools

Every possible combination of a multi-list


list_a = [("A","<",1), ("A","==",5)]
list_b = [("B","<",5), ("B","==",7), ("B",">=",8)]
list_c = [("C","<",10),("C","<=",6),("C",">",4),("C","<=",6)]

I want to make a list of every possible combination with constraint of only one per list admissible.

I can see that itertools.product is somewhat close to what I want, and I know that I could do something like

new_list = []
for a in list_a:
  for b in list_b:
    for c in list_c
      new_list.append(list(itertools.combinations([a,b,c],2)))

But the n**3 complexity here seems like an incredibly poor solution given that I look to do this with eventually 9 lists (i.e., list_c, list_d, list_e, etc...) of size 30+ Here are some acceptable possible outputs:

[("A","<",1)]
[("A","<",1),("B","<",5)]
[("A","<",1),("B","==",7)]
[("A","<",1),("B",">=",8)]
[("A","<",1),("B",">=",8),("C","<",10)]

basically I understand usage of the itertools when you have a select set of numbers, and for example itertools.product(('ABCD'),3) would give outputs of AAA,AAB,AAC,AAD,BAA,BAB,BAC,etc, but I can't seem to figure out how to apply the "only one per list" constraint using the stdlib to the maximal extend without hacking some terribly inefficient solution.


Solution

  • What about:

    import itertools
    
    list_a = [("A","<",1), ("A","==",5)]
    list_b = [("B","<",5), ("B","==",7), ("B",">=",8)]
    list_c = [("C","<",10),("C","<=",6),("C",">",4),("C","<=",6)]
    
    lists = [list_a, list_b, list_c]
    
    
    for l in lists: l.insert(0, None)
    
    for x in itertools.product(*lists):
        print list(filter(None, x))
    

    For those lists I get 60 elements, including an empty element.

    For reference, the index of your example elements are listed below:

    [("A","<",1)]                           # 20
    [("A","<",1),("B","<",5)]               # 25
    [("A","<",1),("B","==",7)]              # 30
    [("A","<",1),("B",">=",8)]              # 35
    [("A","<",1),("B",">=",8),("C","<",10)] # 36