user2109254
user2109254

Reputation: 1759

How to dynamically assign arguments to itertools.product in python

I am trying to work out how to pass itertools.product a dynamic number of arguments.

I have the following code which worked as expected printing out lines with each line having 4 characters in a different order:

#!/usr/bin/env python3.5
import sys, itertools, multiprocessing, functools

alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ12234567890!@#$%^&*?,()-=+[]/;"
num_parts = 4
part_size = len(alphabet) // num_parts

def do_job(first_bits):
    for x in itertools.product(first_bits, alphabet, alphabet, alphabet):
        print(''.join(x))

if __name__ == '__main__':
    pool = multiprocessing.Pool(processes=4)
    results = []

    for i in range(num_parts):
        if i == num_parts - 1:
            first_bit = alphabet[part_size * i :]
        else:
            first_bit = alphabet[part_size * i : part_size * (i+1)]
        pool.apply_async(do_job, (first_bit,))

    pool.close()
    pool.join()

Then I tried to make it completely dynamic using the following code, where the number of alphabet arguments is created on the fly based on the num_parts variable:

#!/usr/bin/env python3.5
import sys, itertools, multiprocessing, functools

alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ12234567890!@#$%^&*?,()-=+[]/;"
num_parts = 4
part_size = len(alphabet) // num_parts
dynamicArgs = []

def do_job(first_bits):
    for x in itertools.product(first_bits, *dynamicArgs):
        print(''.join(x))

if __name__ == '__main__':
    pool = multiprocessing.Pool(processes=4)
    results = []
    for x in range(num_parts-1):
        dynamicArgs.append(alphabet)

    for i in range(num_parts):
        if i == num_parts - 1:
            first_bit = alphabet[part_size * i :]
        else:
            first_bit = alphabet[part_size * i : part_size * (i+1)]
        pool.apply_async(do_job, (first_bit,))

    pool.close()
    pool.join()

But this does not work as expected... it outputs lines with one character on each line and iterates over the alphabet only a single time.

How can I pass a dynamic number of alphabet variables as arguments to itertools.product ?

Thanks for your time.

Upvotes: 2

Views: 1082

Answers (2)

Padraic Cunningham
Padraic Cunningham

Reputation: 180391

You can just multiply the list of strings:

 def do_job(first_bits):

    for x in itertools.product(first_bits, *[alphabet] * 3):

You could also use itertools.repeat:

from itertools import repeat
def do_job(first_bits, times):
    for x in itertools.product(first_bits, *repeat(alphabet, times)):

Upvotes: 1

rrauenza
rrauenza

Reputation: 6963

Is this what you are trying to do?

import sys, itertools, multiprocessing, functools                               

alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ12234567890!@#$%^&*?,()-=+[]/;"

repeats = 5                                                                     

alphabets = [ alphabet ] * repeats                                              

def do_job(first_bits):                                                         

    for x in itertools.product(first_bits, *alphabets):                         
        print(''.join(x))                                                       

do_job('12345')         

You can use the * operator on arrays which repeats the elements.

Output:

1aaaaa
1aaaab
1aaaac
1aaaad
1aaaae
1aaaaf
1aaaag
1aaaah
1aaaai
1aaaaj
1aaaak
[...]

Upvotes: 0

Related Questions