Python – Generate random numbers using the itertools product

Generate random numbers using the itertools product… here is a solution to the problem.

Generate random numbers using the itertools product

I’m using the generator function to create an ordered list of numbers next to itertools.product in order to create all possible pairs of said numbers:

def gen(lowerBound, upperBound, stepSize = 1):
    for steppedVal in np.arange(lowerBound, upperBound, stepSize):
        yield steppedVal

for vectors in it.product(gen(3,6), gen(10,30,5)):
    print(vectors)

This produced such a dataset as expected:

(3, 10)
(3, 15)
(3, 20)
(3, 25)
(4, 10)
(4, 15)
(4, 20)
(4, 25)
(5, 10)
(5, 15)
(5, 20)
(5, 25)

But my problem lies in the next step. I want to add a clause to the generator function to use random numbers in the range instead of step values. When I try the following:

def gen(useRandom, lowerBound, upperBound, stepSize = 1):
    if useRandom:
        randomVal = random.uniform(lowerBound, upperBound)
        yield randomVal
    else:
        for steppedVal in np.arange(lowerBound, upperBound, stepSize):
            yield steppedVal

for vectors in itertools.product(gen(True,3,6), gen(False,10,30,5)):
    print(vectors)

I

see, it’s not what I want :

(4.4163620543645585, 10)
(4.4163620543645585, 15)
(4.4163620543645585, 20)
(4.4163620543645585, 25)

How can I modify this code so that every random number in this dataset is unique without having to change the dataset after the fact, as this adds a huge computational overhead. (The actual dataset contains a dozen variables, each with 10-20 steps).

EDIT, to clarify here is the desired output:

(4.1802347587349857, 10)
(3.7128578913746897, 15)
(5.8912734809721957, 20)
(4.4163620543645585, 25)

Edit 2, to be clearer, I don’t want to use the zip function, as this should also be a possible output :

for vectors in itertools.product(gen(True,3,6), gen(False,10,30,5), gen(False,5,10):
    print(vectors)

(Some Random Number, 10, 5)
(Some Random Number, 10, 6)
(Some Random Number, 10, 7)
(Some Random Number, 10, 8)
(Some Random Number, 10, 9)
(Some Random Number, 15, 5)
(Some Random Number, 15, 6)
(Some Random Number, 15, 7)
(Some Random Number, 15, 8)
(Some Random Number, 15, 9)
(Some Random Number, 20, 5)
(Some Random Number, 20, 6)
(Some Random Number, 20, 7)
(Some Random Number, 20, 8)
(Some Random Number, 20, 9)
(Some Random Number, 25, 5)
(Some Random Number, 25, 6)
(Some Random Number, 25, 7)
(Some Random Number, 25, 8)
(Some Random Number, 25, 9)

The key part is that each pair of the second and third generators remains.

Solution

Your generator calls random.uniform only once. I think you want:

def gen(useRandom, lowerBound, upperBound, stepSize = 1):
    for steppedVal in np.arange(lowerBound, upperBound, stepSize):
        if useRandom:
            randomVal = random.uniform(lowerBound, upperBound)
            yield randomVal
        else:
            yield steppedVal

Now your output becomes:

(4.229914739995998, 10)
(4.229914739995998, 15)
(4.229914739995998, 20)
(4.229914739995998, 25)
(5.52362641577289, 10)
(5.52362641577289, 15)
(5.52362641577289, 20)
(5.52362641577289, 25)
(4.507985392309242, 10)
(4.507985392309242, 15)
(4.507985392309242, 20)
(4.507985392309242, 25)

This indicates that you get three different random values, corresponding to three runs of the first instance of the generator.

Also note that you may want to look at random.randrange, which actually returns a random integer from range(lowerBound, upperBound, stepSize). If you replace random.uniform(lowerBound, upperBound) with random.randrange(lowerBound, upperBound, stepSize) in the generator function, you will get the output:

(5, 10)
(5, 15)
(5, 20)
(5, 25)
(3, 10)
(3, 15)
(3, 20)
(3, 25)
(3, 10)
(3, 15)
(3, 20)
(3, 25)

This time, the generator selects a random number from the set [3,4,5] in each iteration. Note that this doesn’t necessarily produce unique numbers in each iteration! If you’re looking for, you can use random.shuffle.

Related Problems and Solutions