bakiargento
bakiargento

Reputation: 27

best way to loop through randomly generated array

I'm trying to solve a problem where I generate a three random number array and loop through it until the sum of it is below or equal to 21. My question is if there is a better/more performant way to do it than the following, just to adjust myself to the best practices.

rng = np.random.default_rng()
a = 1
while a == 1:
    rints = rng.integers(low=1, high=11, size=3)
    suma = np.sum(rints)
    if (suma <= 21):
        print(rints, suma)
        break

Thanks!

Upvotes: 1

Views: 216

Answers (3)

hpaulj
hpaulj

Reputation: 231375

In numpy we prefer to use whole arrays, and do "many" things at once, rather than iterate.

For example, instead of generating the random numbers just 3 at a time, why not generate a lot (guess 20):

In [88]: rng = np.random.default_rng()
In [89]: rints= rng.integers(low=1, high=11, size=(20,3))
In [90]: rints
Out[90]: 
array([[ 8,  2,  1],
       [ 5,  3,  9],
       [ 5,  3,  6],
       [10,  3,  6],
       [ 4,  9,  1],
       [ 9,  8,  2],
       [ 3,  3, 10],
       [ 1,  3,  5],
       [ 5,  6,  1],
       [ 6,  7,  9],
       [10,  4,  2],
       [ 1,  8,  1],
       [ 6,  7,  8],
       [ 3,  7,  9],
       [ 8, 10, 10],
       [ 7,  6,  8],
       [ 5,  1,  4],
       [ 4,  9, 10],
       [ 1,  8,  8],
       [ 7,  1,  9]])

Then we can sum by 3s, and identify how many are qualify:

In [91]: rints.sum(axis=1)
Out[91]: 
array([11, 17, 14, 19, 14, 19, 16,  9, 12, 22, 16, 10, 21, 19, 28, 21, 10,
       23, 17, 17])
In [92]: np.nonzero(_<=21)
Out[92]: (array([ 0,  1,  2,  3,  4,  5,  6,  7,  8, 10, 11, 12, 13, 15, 16, 18, 19]),)

Judging from this sample, your while will be faster, since there's pretty high probability that an early set will qualify. Other other hand, if the criteria is >21, then we have to generate a lot more to get at least one.

Testing the efficiency of problems who's speed depends on random numbers is difficult, and maybe even meaningless. Depending on the numbers and the condition it could run quickly, or take a long time (e.g. test for sum >=30).

Upvotes: 0

Alexender Iotko
Alexender Iotko

Reputation: 91

Just a shorter form using itertools

import numpy as np
from itertools import dropwhile

rng = np.random.default_rng()
rints = list(dropwhile(lambda x: np.sum(x)>21, rng.integers(low=1, high=11, size=3)))

print(rints, np.sum(rints))

Upvotes: 1

Mitchell van Zuylen
Mitchell van Zuylen

Reputation: 4125

The while loop and the if statement can be combined. This will make it a little more efficient.

rng = np.random.default_rng()
target_value = 21
suma = 999
while suma >= target_value:
    rints = rng.integers(low=1, high=11, size=3)
    suma = np.sum(rints)

I would also suggest posting this to code review. They are more suited to these kind of questions.

Upvotes: 1

Related Questions