How can I make this loop stop at a certain variable occurs - python

I need to write a script that generates random numbers between 1-257000 and stops when a certain number occurs telling me how many numbers it generated so far.
i manged to get this far but can't seem to get it to stop or count
x=1
while x < 257000:
import itertools
import random
def random_gen(low, high):
while True:
yield random.randrange(1, 257000)
gen = random_gen(1, 100)
items = list(itertools.islice(gen, 10))
print items
x = x+1
Thank you so much for your help

Huh. A few flaws (or at least unclear spots) in your code.
You run your loop max 257000 times. Even though the probability is low, there is a chance that you don't hit the number you seek in the loop.
Move your import statements out of your loop, no need to have python check loaded modules each round.
You use a generator for choices of a list (randrange) where you can simply use a randint() call.
You define a closed function within your loop which creates a new function at a new memory address each round.
You slice your results into lists of 10 elements each; is this for printing, or do you actually need your random integers grouped into such lists?
A very simple and straightforward implementation of your described problem could be:
import random
num = 0 # Our counter
certain_number = 123456 # The number we seek
while True: # Run until we break
# Increment for each new step
num += 1
# Generate a single number from the given range
random_number = random.randint(1, 257000)
if random_number == certain_number:
# Break if we hit it
break
print('Hit after {} tries.'.format(num))
>>> Hit after 382001 tries.

First, put your import statements and your function definitons outside your while-loop. That's being super redundant.
>>> def random_gen(low,high):
... while True:
... yield random.randrange(low,high)
...
>>> lucky = 7
>>> rg = random_gen()
>>> rg = random_gen(1,1000)
>>> next(itertools.dropwhile(lambda t: t[1] != lucky, enumerate(rg, 1)))
(811, 7)
>>>
Here's another run, just for fun:
>>> rg = random_gen(1,257000)
>>> n,L = next(itertools.dropwhile(lambda t: t[1] != lucky, enumerate(rg, 1)))
>>> n
22602
>>> L
7
>>>

Related

Save itertools product loop value and then resume from the last result

I'm using this code to break an simple password mycubana, but I want to "pause" the itertools loop so that, after some time, I could resume the loop starting from the last saved itertools.product value. Is there any way to do it without change a lot of the code ?
Code:
import string
from itertools import chain, product
def bruteforce(charset, minlenght, maxlenght):
return(''.join(candidate)
for candidate in chain.from_iterable(product(charset, repeat = i)
for i in range(minlenght, maxlenght)))
contador = 0
for attempt in bruteforce(string.ascii_lowercase, 8, 9):
codigo = 'mycubana'
contador+=1
if attempt==codigo:
print(attempt)
contador=0
Yes, it's actually pretty simple. Using your environment and the definition of bruteforce, the following code will perform two runs of 10 candidates each on the generated sequence:
bf26_8 = bruteforce(string.ascii_lowercase, 8, 9)
count = 0
for c in bf26_8:
count += 1
print(c)
if count == 10:
break
print("======== PAUSED ========")
for c in bf26_8:
count += 1
print(c)
if count == 20:
break
The "trick" is to store the result of bruteforce in a variable. That result is a generator, so if you iterate on it, but do not exhaust it (i.e., break the iteration loop), it will give you the continuations values once you start iterating again.

Generate 100 numbers at once and make it a list and add it to an empty list

I need to generate 100 numbers from 1-500 and append it to an empty list, but I don't know how to fix my code. There is a <'none'> at the end when I print it. And when I used a len function to count a, it only says 1, so it didn't really added the 100 numbers.
a = []
import random
print("original: \n")
for x in range(100):
nums = random.randint(1,501)
b = print(nums, end=" ")
a.append(b)
print(a)
print(len(a))
On python-3.6, you can use random.choices, and extend a by this function's return value:
a.extend(random.choices(range(1, 501), k=100))
Although, if you're starting off with an empty list and adding nothing before this step, it would make more sense to just initialise a as
a = random.choices(range(1, 501), k=100)
Without doing any empty-list initialisation before.
If you're on older versions of python, use random.randint in a loop.
a.extend(random.randint(1, 500) for _ in range(100))
Or,
a = [random.randint(1, 500) for _ in range(100)]
Alternatively,
a = []
for _ in range(100):
a.append(random.randint(1, 500))
From the docs, I believe the upper bound is inclusive (hence, 500).
nums = random.randint(1,501)
This returns a single random number, so the plural name “nums” is misleading here.
b = print(nums, end=" ")
The print function prints something, in this case the generated number, but itself has no return value. So b will be None.
a.append(b)
This could theoretically append the generated number to the list. However, as we established, b is None, so this will append None to the list. Furthermore, this line is outside of the loop, so this will only run once, and would only add a single of your 100 numbers.
You should do something like this instead:
a = []
for x in range(100):
num = random.randint(1,501)
a.append(num)
print(a)
print(len(a))
You can also use a list comprehension here, to make it simpler:
a = [random.randint(1, 501) for x in range(100)]
print(a)
print(len(a))
This will have the same result.
You could also use random.choices which on its own is already capable of generating a list of random numbers with a specified size. So this would work just as well:
a = random.choices(range(1, 501), k=100)
I believe this is what you are looking for. print does not return anything, you cannot add print onto a list. In fact, it's not clear why you need 2 variables for this.
import random
a = []
for x in range(100):
a.append(random.randint(1,501))
print(' '.join(map(str, a)))
print(len(a))
An alternative solution which avoids loops uses the numpy library:
import numpy as np
a = np.random.randint(1, 501, 100)
If performance is an issue; e.g. for many, large random lists; here is benchmarking versus a valid list-based solution using random:
import numpy as np
import random
%timeit np.random.randint(1, 501, 100) # 5.97 µs
%timeit random.choices(range(1, 501), k=100) # 66.3 µs
randint() function generate only one random number. You can generate the random in a for loop 100 times & simulatenosuly append in the list so when outside the for loop ,the list 'a' have the 100 random numbers & this can be verified through length len() function .
Also I am attach the screenshot of the output.
a = []
import random
print("original: \n")
for x in range(100):
nums = random.randint(1,501)
a.append(nums)
print("Numbers : " , a)
print("Length : " , len(a))
Your code was correct just a little mistake that is you don't have indented the a.append(nums), So that become out side the scope of for loop. Try this code :) .
import random
a = []
print("original: \n")
for x in range(100):
nums = random.randint(1,501)
print(nums, end=" ")
a.append(nums)
print(a)
print(len(a))

Why is itertools.islice only returning one value, when I entered 10 as the stop parameter?

I'm trying to write a program that will print 10 random dice rolls. This is my code:
import itertools
from random import randint
def gen_rndtup(n):
a = randint(1,n-1)
b = randint(1, n-2)
yield (a, b)
if __name__=='__main__':
n = 7
dice_roll = itertools.islice(gen_rndtup(n), 10)
print(list(dice_roll))
This is the output I get: [(4, 2)] (obviously the numbers are different every time, due the random number generator).
From what I read in the documentation, itertools.islice(gen_rndtup(n), 10) should return the first 10 tuples generated by gen_rndtup(n), so why is it only returning one?
Because gen_rndtup only yields one tuple. If you want gen_rndtup to give you more than one value, you need it to yield multiple times (either by having multiple yield statements or by putting your yield in some kind of loop).
Your generator yields one result and then stops yielding results.
def gen_rndtup(n):
a = randint(1,n-1)
b = randint(1, n-2)
while True:
yield (a, b)
will produce the what you expect

Python how to run this function to get 100 primes

I have this code I want to run:
def genPrimes():
primes = [] # primes generated so far
last = 1 # last number tried
while True:
last += 1
for n in primes:
if last % n == 0:
break
else:
primes.append(last)
yield last
n = genPrimes()
How would I implement this to return a list of 100 primes?
This is a generator. If you correct the indentation, you can use it in a for-loop, or use islice to get the first 100 primes:
from itertools import islice
def genPrimes():
primes = [] # primes generated so far
last = 1 # last number tried
while True:
last += 1
for n in primes:
if last % n == 0:
break
else:
primes.append(last)
yield last
primes = list(islice(genPrimes(), 100))
try: [n.next() for x in range(100)]
This code is a bit cryptic. I also don't think it does anything.
Your else is attached to your while which would only execute if you hit a break. Clever but cryptic. However, you initialize your list to [] and then do a loop though it. Looping through an empty list skips the body of the loop, which means the break will never execute. Since the break will never execute, the generator will never yield anything.
Thus, this is an infinite loop that does nothing.

List Index Out of Range in Python; Iteration

I am using the simple program below to see how long an iterative process takes to terminate. However, in line 15, I cannot figure out why I am getting index out range error.
An example of what I am trying to count is the number of steps it takes for the following example iteration: User inputs 4 and then 1234. Then we have: [1,2,3,4] --> [1,1,1,1] --> [0,0,0,0] and then termination. 2 steps is required to get to [0,0,0,0]. I have proven that for the values of n that I am inserting, the system goes to [0,0,0,0] eventually.
import math
index = input("Enter length: ")
n = int(index)
game = input("Enter Coordinates of length n as a number: ")
s = list(game)
Game = []
for k in s:
Game.append(int(k))
l = len(game)
while sum(Game) > 0:
Iteration = []
k = 0
j = 0
while j < l-1:
Iteration.append(math.fabs(Game[j]-Game[j+1])) # line 15
j = j+1
k = k+1
Game = Iteration
print(k)
Game = Iteration is probably why. When j = 1, Game will be a list with only one item because of that. Then, Game[1]-Game[2] will be out of bounds.
Your code is written in a very un-Pythonic style that suggests you're translating directly from C code. (Also, you should basically never use input(); it's insecure because it evaluates arbitrarily user-entered Python code! Use raw_input() instead.)
If you rewrite it in a more Pythonic style, it becomes clear what the problem is:
import math
# you don't do anything with this value, but okay
s = index = int(raw_input("Enter length: "))
# game/Game naming will lead to confusion in longer code
game = raw_input("Enter Coordinates of length n as a list of comma-separated numbers: ")
Game = [int(k) for k in game.split(',')]
l = len(Game)
while sum(Game) > 0:
Game = [math.fabs(Game[j]-Game[j+1]) for j in range(l-1)] # problem here
# no idea what k is for, but it's not used in the loop anywhere
The problem is that in every iteration through your inner while loop, or the line marked # problem here in my version, your Game list gets shorter by one element! So on the second time through the outer while loop, it reads an element past the end of Game.
I have no idea what this code is trying to do, so I can't really suggest a fix, but if you truly intend to shorten the list on every pass, then you of course need to account for its shorter length by putting l=len(Game) inside the while loop.

Categories