function not returning list - python

I have a simple script to generate UK lottery numbers (7 numbers, 1 to 49 inclusive).
My code has a function that generates 7 random numbers into a list, runs set on the list removing duplicate numbers, checks if there are still 7 members in the list, and if not the function calls itself to generate 7 new numbers.
However, when the function calls itself it does not return the list.
I'd appreciate knowing what I'm doing wrong here.
from random import randint
def lotto():
l = []
for r in range(1,8):
l.append(randint(1,49))
print "DEBUG: l=", l
print "DEBUG: set(l)=", set(l), len(set(l))
if(len(set(l)) !=7):
lotto()
else:
print "Before return l, l = ", l
return l
def main():
numbers = lotto()
print numbers
Here is a sample run that does not work correctly:
DEBUG: l= [44, 32, 12, 12, 33, 16, 31]
DEBUG: set(l)= set([32, 33, 44, 12, 16, 31]) 6
DEBUG: l= [46, 20, 10, 24, 16, 35, 44]
DEBUG: set(l)= set([35, 10, 44, 46, 16, 20, 24]) 7
Before return l, l = [46, 20, 10, 24, 16, 35, 44]
None
And a sample run that does work correctly:
DEBUG: l= [20, 5, 21, 37, 10, 44, 38]
DEBUG: set(l)= set([37, 38, 10, 44, 20, 21, 5]) 7
Before return l, l = [20, 5, 21, 37, 10, 44, 38]
[20, 5, 21, 37, 10, 44, 38]

You're not returning the result of the recursive call.
if(len(set(l)) !=7):
return lotto()

The recursive call
lotto()
does not actually return the value returned by lotto(). You'd need to use
return lotto()
instead. (Note that instead of the tail-recursive call, a loop would be preferable.)
That said, there is a much easier solution to your actual problem, namely random.sample(). Python2.x version:
import random
print random.sample(xrange(1, 50), 7)
Python 3.x version:
import random
print(random.sample(range(1, 50), 7))

Related

Whats the most Pythonic way to pass a large number of arguments to multiprocessing map?

I'm trying to run a stochastic simulation in parallel using Python's multiprocessing library 50 times, and compare the parallel execution time to the sequential execution time.
I've written a function that calls my stochastic simulation function, parallelfunc this is passed as the first argument to the multiprocessing map command.
def parallelfunc(v):
gillespie_tau_leaping(start_state, LHS, stoch_rate, state_change_array)
At the moment the second argument to map is as follows:
if __name__ == '__main__':
#para_proc = list(range(50))
start = datetime.utcnow()
with Pool() as p:
pool_results = p.map(parallelfunc, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50])
end = datetime.utcnow()
sim_time = end - start
print(f"Simualtion utc time:\n{sim_time}")
I've tried a few methods to pass an iterable of length 50 as the second argument to map, including a list in the form of para_proc this didn't work.
I then tried a list comprehension [x for x in range(50)] only I think the for loop really slowed down the execution time and it wasn't much faster than running the simulation 50 times sequentially which isn't what I want.
Is there a more Pythonic way that won't heavily impact the speed to do this?
Cheers

find second duplicate and period in a python list

I've a python list as this one [2, 5, 26, 37, 45, 12, 23, 37, 45, 12, 23, 37, 45, 12, 23, 37]. The real list is really long. The list repeat itself after a certain point in this case after 37. I have no problem finding the number at which it repeats, but i need to truncate the list at the second one. In this case the result would be [2, 5, 26, 37, 45, 12, 23, 37]. For finding the number (37 in this case) i use a function firstDuplicate() found on stackoverflow. Someone can help me ?
def firstDuplicate(a):
aset = set()
for i in a:
if i in aset:
return i
else:
aset.add(i)
pass
pass
pass
LIST = LIST[1:firstDuplicate(LIST)]
You can use the same basic idea of firstDuplicate() and create a generator that yields values until the dupe is found. Then pass it to list(), a loop, etc.
l = [2, 5, 26, 37, 45, 12, 23, 37, 45, 12, 23, 37, 45, 12, 23, 37]
def partitionAtDupe(l):
seen = set()
for n in l:
yield n
if n in seen:
break
seen.add(n)
list(partitionAtDupe(l))
# [2, 5, 26, 37, 45, 12, 23, 37]
It's not clear what should happen if there are no dupes. The code above will yield the whole list in that case.
A function to find the period size and length of repeated numbers should start from the end of the sequence of numbers. This will make it easier to ensure that there is a cycle up to the end of the list and avoid any concerns over non-periodic repetitions at the beginning of the list.
For example:
def getPeriod(seq):
lastPos = { n:p for p,n in enumerate(seq) }
prevPos = { n:p for p,n in enumerate(seq) if p<lastPos[n] }
period = 1
for n in reversed(seq):
if n not in prevPos: break
delta = lastPos[n] - prevPos[n]
if delta%period == 0 or period%delta == 0:
period = max(delta,period)
else: break
nonPeriodic = (i for i,(n,p) in enumerate(zip(seq[::-1],seq[-period-1::-1])) if n != p)
periodLength = next(nonPeriodic,0)
return period, periodLength
output:
seq = [2, 5, 26, 37, 45, 12, 23, 37, 45, 12, 23, 37, 45, 12, 23, 37]
period, periodLength = getPeriod(seq)
print(period,periodLength) # 4 9
print(seq[:-periodLength]) # [2, 5, 26, 37, 45, 12, 23]

Python function that generates random arrays of integers not working

I need to create a function that generates random arrays of integers between a and b, inclusive, where a and b define the range and M and N define the size of the output array. I've done something but it seems that it's not properly working and I don't know exactly how can I define the size of the output array, where exactly to put M and N.....Here it's my code:
import random
def Rand(start, end, num):
res = []
for j in range(num):
res.append(random.randint(start, end))
return res
# Driver Code
num = 10
start = 20
end = 40
print(Rand(start, end, num))
You just need two nested loops (or a nested list comprehension)
For example:
import random
def random_array(start, end, a, b):
return [[random.randint(start, end) for _ in range(a)] for _ in range(b)]
# Driver Code
a = 10
b = 5
start = 20
end = 40
print(random_array(start, end, a, b))
Which, in my case, output:
[[35, 27, 30, 27, 26, 37, 38, 27, 36, 34], [24, 24, 29, 35, 27, 38, 38, 37, 24, 24], [35, 20, 38, 25, 26, 20, 31, 29, 27, 33], [37, 36, 34, 20, 27, 30, 33, 26, 24, 26], [28, 35, 20, 31, 33, 36, 29, 25, 36, 36]]
If you don't want to use list comprehensions (although you probably should), it would be the equivalent of:
def random_array(start, end, a, b):
res = []
for _ in range(b):
inner = []
for _ in range(a):
inner.append(random.randint(start, end))
res.append(inner)
return res
Final note: According to PEP-8 you shouldn't start a function name with a capital letter.

How to loop through an entire list randomly before looping again?

import random
list1 = [11, 22, 33, 44, 55]
for i in range(5):
random_number = random.randint(0,4)
print(list1[random_number])
I am trying to find a way to print an entire list randomly without printing duplicates of the list in the first loop. Then if I increase the range to 10, 15, 20, and so on, every 5 prints displays all the elements randomly and without duplicates(by duplicates i mean no duplicates for every group of 5 prints displayed) i.e. 22, 33, 11, 55, 44, 44, 11, 33, 22, 55, 33, 22, 55, 44, 11 ...
you could make a copy of the list, then pop elements out of the copy until it's empty, then 'reload' it by copying the original list again
import random
list1 = [11, 22, 33, 44, 55]
clonedList = list1.copy()
for i in range(5):
if len(clonedList == 0):
clonedList = list1.copy()
random_number = random.randint(0,len(clonedList)-1)
print(clonedList.pop(random_number))

how to check if an element exists in a list of lists python

I have a list of lists that correspond to lines in file, with multiple columns.
[ [col1, col2, col3], [elem1, elem2, elem3], [elem4, elem5, elem6] ]
I want to check if (for example) elem3 is in any of the lists, and if it is, go into that list. (really I have a list of things I need to check, so it's a list that probably contains elem3, elem5, elem7.... etc)
the shortest way is to use list comprehensions and list comprehensions sometimes are more faster than simple for loop
your list:
list1 = [ ["col1", "col2", "col3"], ["elem1", "elem2", "elem3"], ["elem4", "elem5", "elem6"] ]
your element to find:
to_find = "col1"
your function to "go into that list":
def do_something(sub_list):
print (sub_list)
and the list comprehension that will find your element and call function with list that have it:
[do_something(sub_list) for sub_list in list1 if to_find in sub_list]
You can do something like this:
def in_list(list_of_lists, item):
for list_ in list_of_lists:
if item in list_:
return list_
EDIT:
Here is a recursive version for the heck of it:
def in_list(list_of_lists, item):
if not list_of_lists:
return None
if item in list_of_lists[0]:
return list_of_lists[0]
return in_list(list_of_lists[1:], item)
I came across a similar problem. I had a list of tuples, with tile numbers:
data = [(0, 0, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 0),
(0, 23, 24, 25, 26, 27, 28, 29, 30, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 0),
(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21)]
I needed to find out where in the list of tuples a particular tile number is located, so:
to_find = 42
for i in range(len(data)):
if to_find in data[i]:
print (i, data[i].index(to_find))
break

Categories