2

I am trying to print out all the possible combinations of two lists, so for example if list1 has values {1,2,3} and list two has values {A,B,C} I should get the following:

A=1 B=1 C=1
A=1 B=1 C=2
A=1 B=1 C=3
A=1 B=2 C=1
A=1 B=2 C=2
A=1 B=2 C=3
A=1 B=3 C=1
A=1 B=3 C=2
A=1 B=3 C=3
etc

For all of the possible values in the list. So the last line should be

A=3 B=3 C=3

Now this should work for abititary sized arrays. So if I have list1 = {1,2,3,4,5,6} list2 = {A,B,C,D,E,F}

I should get

A=1 B=1 C=1 D=1 E=1 F=1
A=1 B=1 C=1 D=1 E=1 F=2
A=1 B=1 C=1 D=1 E=1 F=3
A=1 B=1 C=1 D=1 E=1 F=4
A=1 B=1 C=1 D=1 E=1 F=5
A=1 B=1 C=1 D=1 E=1 F=6
A=1 B=1 C=1 D=1 E=2 F=1
A=1 B=1 C=1 D=1 E=2 F=2
A=1 B=1 C=1 D=1 E=2 F=3
A=1 B=1 C=1 D=1 E=2 F=4
A=1 B=1 C=1 D=1 E=2 F=5
A=1 B=1 C=1 D=1 E=2 F=6
etc

So in the first example there would be 3^3 = 27 combinations and I attempted to solve the problem like:

def printArrays():
    letters = {'A', 'B', 'C', 'D', 'E', 'F'}
    domain = {1, 2, 3, 4, 5, 6}
    myStr = ""
    for value in domain:
        for letter in letters:
            myStr += letter + "=" + str(value) + " "
        myStr += "\n"
    print(myStr)

Obviously it gives the wrong output since it gives me:

F=1 D=1 C=1 B=1 E=1 A=1 
F=2 D=2 C=2 B=2 E=2 A=2 
F=3 D=3 C=3 B=3 E=3 A=3 
F=4 D=4 C=4 B=4 E=4 A=4 
F=5 D=5 C=5 B=5 E=5 A=5 
F=6 D=6 C=6 B=6 E=6 A=6 

What would be the correct way to solve this problem?

Note: That I would also want a solution that does not involve any libraries as I am trying to learn recursion so a recursive solution would be appreciated.

7
  • Just change the order of the two for loops. Commented Oct 13, 2022 at 4:10
  • nope. that doesn't solve it Commented Oct 13, 2022 at 4:10
  • itertools is a built in library - not external Commented Oct 13, 2022 at 4:13
  • Oh... I did not notice. You used set { }. Just use list [] instead Commented Oct 13, 2022 at 4:15
  • 1
    the data stored in the set is unordered. While the data stored in the list is ordered. Commented Oct 13, 2022 at 4:16

4 Answers 4

4

what you're doing is iterating through letters * domain. What you want is to iterate though letters ^ len(domain).

I'll use itertools.product for this since it's built explicitly for combinatorial products:

import itertools

def printArrays():
    letters = {'A', 'B', 'C', 'D', 'E', 'F'}
    domain = {1, 2, 3, 4, 5, 6}
    myStr = ""
    for current in itertools.product(domain, repeat=len(letters)):
        for k, v in zip(letters, current):
            myStr += k + "=" + str(v) + " "
        myStr += "\n"
    print(myStr)

This prints what you're looking for:

E=1 D=1 F=1 B=1 A=1 C=1
E=1 D=1 F=1 B=1 A=1 C=2
E=1 D=1 F=1 B=1 A=1 C=3
E=1 D=1 F=1 B=1 A=1 C=4
E=1 D=1 F=1 B=1 A=1 C=5
E=1 D=1 F=1 B=1 A=1 C=6
E=1 D=1 F=1 B=1 A=2 C=1
E=1 D=1 F=1 B=1 A=2 C=2
E=1 D=1 F=1 B=1 A=2 C=3
E=1 D=1 F=1 B=1 A=2 C=4
E=1 D=1 F=1 B=1 A=2 C=5
E=1 D=1 F=1 B=1 A=2 C=6
E=1 D=1 F=1 B=1 A=3 C=1
...
E=6 D=6 F=6 B=6 A=6 C=2
E=6 D=6 F=6 B=6 A=6 C=3
E=6 D=6 F=6 B=6 A=6 C=4
E=6 D=6 F=6 B=6 A=6 C=5
E=6 D=6 F=6 B=6 A=6 C=6
Sign up to request clarification or add additional context in comments.

1 Comment

Is there a way to do this without libraries as I am trying to learn recursion.
2

The value assignment is like Cartesian product of list1, so using itertools.product.

import itertools

list1 = [1, 2, 3]
list2 = ['A', 'B', 'C']
assignment_list = itertools.product(list1, repeat=len(list2))
buffer = ""
for assignment in assignment_list:
    for var, val in zip(list2, assignment):
        buffer += f"{var}={val} "
    buffer += "\n"
print(buffer)

1 Comment

good call with using the repeat argument of itertools.product!
1

This addresses the problem with a recursive approach:

def add_domain_for_remaining_letters(letters, domain, prefix=""):
    # termination condition:
    # if no remaining letters, just return the prefix
    if len(letters) == 0:
        return prefix + "\n"

    # otherwise, loop over each i in the domain
    # and recurse for each remaining letter
    result = ""
    for i in domain:
        result += add_domain_for_remaining_letters(
            letters=letters[1:], domain=domain, prefix=f"{prefix}{letters[0]}={i} "
        )
    return result

This gives the desired output as a string:

In [20]: print(add_domain_for_remaining_letters(letters=["A", "B"], domain=[1, 2]))
A=1 B=1
A=1 B=2
A=2 B=1
A=2 B=2


In [21]: print(add_domain_for_remaining_letters(letters=["A", "B", "C", "D"], domain=[1, 2, 3]))
A=1 B=1 C=1 D=1
A=1 B=1 C=1 D=2
A=1 B=1 C=1 D=3
A=1 B=1 C=2 D=1
...
A=3 B=3 C=2 D=1
A=3 B=3 C=2 D=2
A=3 B=3 C=2 D=3
A=3 B=3 C=3 D=1
A=3 B=3 C=3 D=2
A=3 B=3 C=3 D=3

Comments

1

Notice that A=, B=, C= is the same for every row. As others have pointed out the numbers are just the cartesian product of the set of numbers. With that in mind, you could make a simple recursive function to handle the product, and then zip in the letters. Python generators allow you to do this in a memory efficient way — you don't need to store all the combinations in memory:

n = [1,2,3]
keys = ['A','B','C']

# Generate product
def rec_product(l, r):
    if r > 1:
        yield from ((*t, n) for t in rec_product(l, r-1) for n in l)
    else:
        yield from ((n,) for n in l)

# add the letters and print
for p in rec_product(n, len(n)):
    print(*(f'{k}={v}' for k, v in zip(keys, p)))

This will print:

A=1 B=1 C=1
A=1 B=1 C=2
A=1 B=1 C=3
…
A=3 B=3 C=2
A=3 B=3 C=3

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.