AlbaTroels
AlbaTroels

Reputation: 290

Getting combinations for content of x lists in Python

My head is about to explode.

I have x lists that each has y length, like this:

    list1 = ["text11","text12", "text13"]
    list2 = ["text21","text22", "text23"]
    list3 = ["text31","text32"]

I'm trying to get a list containing string concatenations of all the "combinations" of the content from each list, seperating them with a "+":

    listFinal = ["text11 + text21 + text31",
                 "text11 + text21 + text32",
                 "text11 + text22 + text31",
                 "text11 + text22 + text32",
                 "text11 + text23 + text31",
                 "text11 + text23 + text32",
                 ...
                 "text13 + text23 + text32",

I can make it work if the length and the number of the lists are constant using nested loops, but as the lists might vary in quantity and length, i cannot for the love of god figure out how to do this.

Among a lot of things, I have tried making a list containing my lists and then using nested loops where i try to perform the action for the length of the big list. This gives me only "pairwise" combinations.

list = [list1, list2, list3]
for l in range(len(list)):
    for li in list[l]:
        for lii in list[l+1]:
            print("li",li,"lii",lii)

This is super hard for me to explain, but I hope it makes somewhat sense.

Any suggestions on how i can make it output my final list with varying sizes and length of the sublists? Thank you in advance

Upvotes: 1

Views: 55

Answers (4)

I'mahdi
I'mahdi

Reputation: 24049

You can use itertools.product and add '+' between elements that gets from product like below.

Try this:

import itertools

list1 = ["text11","text12", "text13"]
list2 = ["text21","text22", "text23"]
list3 = ["text31","text32"]
list4 = ["text41","text42","text43"]
list5 = ["text51","text52","text53"]

lists = [list1] + [list2] + [list3] + [list4] + [list5]

final_list = ['+'.join(pr) for pr in (itertools.product(*lists))]

Output:

>>> final_list

['text11+text21+text31+text41+text51',
 'text11+text21+text31+text41+text52',
 'text11+text21+text31+text41+text53',
 'text11+text21+text31+text42+text51',
 'text11+text21+text31+text42+text52',
 'text11+text21+text31+text42+text53',
 'text11+text21+text31+text43+text51',
 'text11+text21+text31+text43+text52',
 'text11+text21+text31+text43+text53',
 'text11+text21+text32+text41+text51',
 'text11+text21+text32+text41+text52',
 'text11+text21+text32+text41+text53',
 'text11+text21+text32+text42+text51',
 'text11+text21+text32+text42+text52',
 'text11+text21+text32+text42+text53',
 'text11+text21+text32+text43+text51',
 'text11+text21+text32+text43+text52',
  ...
 'text13+text23+text32+text42+text53',
 'text13+text23+text32+text43+text51',
 'text13+text23+text32+text43+text52',
 'text13+text23+text32+text43+text53']

For more details:

>>> list(itertools.product(*lists))

[('text11', 'text21', 'text31', 'text41', 'text51'),
 ('text11', 'text21', 'text31', 'text41', 'text52'),
 ('text11', 'text21', 'text31', 'text41', 'text53'),
 ('text11', 'text21', 'text31', 'text42', 'text51'),
 ('text11', 'text21', 'text31', 'text42', 'text52'),
 ('text11', 'text21', 'text31', 'text42', 'text53'),
 ('text11', 'text21', 'text31', 'text43', 'text51'),
 ('text11', 'text21', 'text31', 'text43', 'text52'),
 ('text11', 'text21', 'text31', 'text43', 'text53'),
 ...
]

Upvotes: 2

Brandon Feder
Brandon Feder

Reputation: 21

You are so close!!!! You said you can only do it when all the lists have the same length. Why not make this the case? Maybe use a "place-holder" character that you remove after forming the combinations? I'll let you think about that. ;-)

FYI: The approach I just hinted to will work, but it is not the most efficient. If you want to find the "correct" way to do it, I would look into recursion.

I noticed that you named one of your variables list. This is not a good idea because list is an already defined function. After you replace it's value, you may not be able to call it this may be okay in your program, but is generally bad practice and can cause unwanted side-effects.

The answers of the other people are correct, but I would suggest writing the function that finds the combinations yourself before using already written code. If you use that principal in general, you'll learn a lot more much quicker.

Have a great day!

Upvotes: 0

NoCommandLine
NoCommandLine

Reputation: 6263

  1. Combine the lists into a single list

  2. Then use the inbuilt combinations function

    from itertools import combinations

    # Combine all 3 lists into 1 list
    list4 = list1 + list2 + list3
    
    # Get all combinations of length 3 (since you want the items from the 3 lists)
    combos = combinations(list4,3)

    # Print the combinations
    for a in list(combos):
        # Since you want them separated by "+", use "+" to join each list
        print (" + ".join(a))

Upvotes: 1

marcel h
marcel h

Reputation: 788

Besides sorting of list entries, the following might be what you are looking for:

list1 = ["text11", "text12", "text13"]
list2 = ["text21", "text22", "text23"]
list3 = ["text31", "text32"]

my_list = [list1, list2, list3]

tmp = set(my_list[0])
for i in range(1, len(my_list)):
    tmp = [x + '+' + y for x in tmp for y in my_list[i]]
    
print(tmp)

Output:

['text13+text21+text31', 'text13+text21+text32', 'text13+text22+text31', 'text13+text22+text32', 'text13+text23+text31', 'text13+text23+text32', 'text12+text21+text31', 'text12+text21+text32', 'text12+text22+text31', 'text12+text22+text32', 'text12+text23+text31', 'text12+text23+text32', 'text11+text21+text31', 'text11+text21+text32', 'text11+text22+text31', 'text11+text22+text32', 'text11+text23+text31', 'text11+text23+text32']

Upvotes: 1

Related Questions