Python random.randrange producing everything but the step - python

When using this following code:
import random
sticks = 100
randomstep = random.randint(1, 6)
expertmarbles = random.randrange(1, sticks, 2**randomstep)
the output is producing everything excluding the step, so for example i would like this to output a random from these numbers: 2,4,8,16,32,64. However it will output everything but these numbers. Can anyone offer any advice, the reason i'm using variables here is because the amount of sticks will decrease.

Instead of using random.randrange you could use random.choice (docs):
import random
min_power = 1
max_power = 6
print(random.choice([2**i for i in range(min_power, max_power + 1)]))

You can try this
def myRand(pow_min,pow_max):
return 2**random.randint(pow_min,pow_max)
I would suggest you to use this instead of random.choice, which requires you to generate a list, which is unnecessary.

Related

How do I get random numbers that fully cover a range?

I'm trying to have random integers between (1,5) but the catch is displaying all of the values from the random integer in a for loop ranging of 10 loops. I only have access to randint() and random() methods in 'random class'.
from random import randint
eventList = []
taskList = []
dayList = []
def getEventList():
eventList.sort()
return eventList
def getTaskList():
return taskList
def getDayList():
return dayList
def generateData():
while len(getTaskList()) < 10:
# Need to implement a way to stretch the random int while having all the integers present
randomEvent = randint(1, 5)
randomTask = randint(10, 30)
randomDay = randint(1, 9)
eventList.append(randomEvent)
dayList.append(randomDay)
if randomTask not in getTaskList():
taskList.append(randomTask)
Based on clarifications in my other answer, I think you meant to ask "how to I get random numbers that fully cover a range?"
You are using randint, and just calling it extra times hoping to get all the values. But depending on random chance, that can take a while.
It would be better to just take all the values you want, e.g. list(range(1,6))
and then just rearrange that with random.shuffle
https://docs.python.org/3/library/random.html#random.shuffle
import random
values = list(range(1, 6))
random.shuffle(values)
print(values)
Obviously, if this is what you want to do, but your prof says you can't use that function, then you should use that function, get working code, and only THEN write your own replacement for the standard library. (so you only have to debug one or the other)
So write your own version of shuffle. I'll leave the details to you, but it should be pretty easy to use randint to pick one of the available entries, removing it, and so on.
In order to sort things, you need "things" to sort. Therefore you must group together all three numbers in a single entity, and then sort those entities. I suggest you use a Task class, and let it handle things like generating a unique task number. Avoid global variables.
Here is a minimal reproduction (based on your code) of just taking your three numbers in a tuple, combining them with the builtin "zip" and sorting that:
from random import randint
def generateData():
eventList = []
taskList = []
dayList = []
for _ in range(10):
randomEvent = randint(1, 5)
randomTask = randint(10, 30)
randomDay = randint(1, 9)
eventList.append(randomEvent)
taskList.append(randomTask)
dayList.append(randomDay)
return sorted(zip(eventList, taskList, dayList))
for task in generateData():
print(task)
Also note that python convention for variable names is a little different, but I left that alone and used your names.

How do I create a random number based on a seed without using random.seed()?

I know that you can do this:
random.seed(100)
r = random.randint(1, 3)
But is it possible to do something more similar to this?
r = random.randint(1, 3, seed=100)
Also I am aware that the code above would give the same output every time, that is the behavior I want.
Create your own RNG with the seed you want, and call its randint method:
r = random.Random(100).randint(1, 3)
Put random() inside a wrapper. I can't write Python, so this is pseudocode:
myRandom(lo, hi, mySeed)
random.seed(mySeed)
return random.randint(lo, hi)
I will leave converting that to correct Python as an exercise.

Using Timeit within a while loop and increasing input size

I'm stumped. Basically, I have two functions that take an input (which is a list of randomly generated numbers).
Then I wanted to figure out the size of the input list in which the time it takes both functions to execute is equal.
Here's what I have:
def function1(inputlist):
#does something to inputlist
def function2(inputlist):
#does same thing to inputlist as before but in different way
time1 = timeit.timeit(stmt="function1(random.sample([x for x in range(0, 20000), 10)",setup = "from file import function1,input",number=100)
time2 = timeit.timeit(stmt="function2(random.sample([x for x in range(0, 20000), 10)",setup = "from file import function2,input",number=100)
i=0
while time1<time2:
time1 = timeit.timeit(stmt="function1(random.sample([x for x in range(0, 20000), i)",setup = "from file import function1",number=100)
time2 = timeit.timeit(stmt="function2(random.sample([x for x in range(0, 20000), i)",setup = "from file import function2",number=100)
i = i+1
print(i)
I can't figure this out. I've tried everything I could find. I know you can't reference outside variables when using timeit, so I tried working around that too. I basically need any sort of method where I can increase the input side of the function and calculate each time.
Thanks so much in advance. I've been struggling on this for over a day now.
I think the easiest way here, would be to format the string accordingly:
Instead of
stmt="function1(random.sample([x for x in range(0, 20000)], i))"
write
stmt=f"function1(random.sample([x for x in range(0, 20000)], {i}))"
This will put the current value of i where {i} stands. See the docs for further information.

Picking random integer not in a list between range

I need to randomly pick an integer between two integers but that integer can't be in a list.
This is how I am doing it:
bannedReturningCustomersIndex = []
index = next(iter(set(range(0, 999)) - set(bannedReturningCustomersIndex)))
#some code..
bannedReturningCustomersIndex.append(index)
The problem is that I'm not pickig the integer randomly, I'm picking them 1 by 1 from the beginning...
Use random.choice after converting to a list:
import random
bannedReturningCustomersIndex = []
valid_indexes = list(set(range(0, 999)) - set(bannedReturningCustomersIndex))
bannedReturningCustomersIndex.append(random.choice(valid_indexes))
Even though the previous answer is correct, I'd like to propose the following approch, which is more readable, flexible and separates the logic from your main code.
import random
def iterRandNonBannedCustomers(banned_idx, c_idx=range(0, 999)):
c_idx = list(c_idx)
random.shuffle(c_idx)
return filter(lambda i: i not in banned_idx, c_idx)
The function returns an iterator over all non-banned customers. Use it, for example, like this:
for customer in iterRandNonBannedCustomers(bannedReturningCustomersIndex):
# do stuff

generating promotion code using python

By using python language, what would be a clever / efficient way of generating promotion codes.
Like to be used for generating special numbers for discount coupons.
like: 1027828-1
Thanks
The following isn't particularly pythonic or particularly efficient, but it might suffice:
import random
def get_promo_code(num_chars):
code_chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
code = ''
for i in range(0, num_chars):
slice_start = random.randint(0, len(code_chars) - 1)
code += code_chars[slice_start: slice_start + 1]
return code
1027828-1 is extremely small. An attacker can make a ~million guesses using only a couple lines of code and maybe a few days.
This is a good way to produce a hard to predict number using python, it works under linux and windows. It is base64'ed for binary safety, depending what you are doing with it you might want to urllib.urlencode() but I would avoid base10 because it doesn't store as much information.
import os
import base64
def secure_rand(len=8):
token=os.urandom(len)
return base64.b64encode(token)
print(secure_rand())
As a side note this is generating a full byte, which is base256. 256^8 is 18446744073709551616 which should be large enough.
As it was pointed out base64 isn't a very good token for humans to use. Consider an alternate encoding like url-safe base64 or perhaps humanhash as they would be easier to type in.
if you need a 6-digit # you could do this until you found a unique value:
import random
print str(random.randint(100000, 999999))
or go sequentially...
Try this:
import random
coupon = open("coupons.txt", "a")
def generate(amount):
for x in range(0, amount):
a = random.randint(1000, 9999)
a = str(a)
b = random.randint(1000, 9999)
b = str(b)
c = random.randint(1000, 9999)
c = str(c)
total = ""
total = str(total)
total = a + " " + b + " " + c
coupon.write(total)
coupon.write("\n")
amount = int(input("How many coupons do you want to generate: "))
generate(amount)
coupon.close()
print("\nCode's have been generated!")
You can make the coupons as long as you want. They save into a txt file called coupons.txt also.
I've come up with an answer for this that I think is fairly clever, but relies on a couple of assumptions that might not be true for your situation.
The resulting code is purely numeric.
The resulting code is technically variable-length; [10, 20].
If these work for you, then so might this solution:
def code(seed = None):
if (not seed) or (type(seed) != str) or (len(seed) < 10):
seed = str(uuid.uuid4())[:10]
code = ""
for character in seed:
value = str(ord(character))
code += value
return code[:20]
In this function, a string-typed seed is used as the base of the code. For each character in the string, convert it into its ASCII representation, then append it to the code.
By default, the function yields codes like this: '97534957569756524557', and can be invoked with any arbitrary seed. For example...
code("pcperini's answer") == '11299112101114105110'
code(str(time.time())) == '49524956514950505257'

Categories