I have a query relating to return only the last results, so here is my code:
import random
def Step_1():
Start_Game = raw_input("Enter \'Start' to continue \n")
if Start_Game == 'start':
print "Let the Lottery begin"
else:
return Step_1()
#-------------------------------------------------------------------
def Step_2():
random_list = []
for i in range(10):
while len(random_list) < 6:
random_number = random.randint(1,59)
while random_number not in random_list:
random_list.append(random_number)
print random_list
Step_1()
Step_2()
When i run this it gives me the below result,
Enter 'Start' to continue
start
Let the Lottery begin
[56]
[56, 20]
[56, 20, 32]
[56, 20, 32, 2]
[56, 20, 32, 2, 23]
[56, 20, 32, 2, 23, 30]
However how can i just display the last result generated and discard the previous 5. I know i need to change the last bit "print" within my Step_2 function, but what do I need to add?
Thanks .
A one liner:
random.sample(range(1, 59), 6) # genrates 6 unique random no's in the range
OR to modify existing code, use a list to store previously generated random no's
def Step_2():
random_list=[]
for i in range(6):
random_number = random.randint(1,59)
while random_number in random_list:
random_number = random.randint(1,59)
print random_number
list.append(random_number )
For your step2() function you will probably want to use a while loop, since you do not really know, how many random numbers you need to generate until you have 6 unique numbers.
def step2():
# Declare an empty list to hold the random numbers
numbers = []
# While we do not have 6 numbers in our list
while len(numbers) < 6:
# Generate a random number
rndnum = random.randint(1,59)
# If that random number is not yet in our list
if rndnum not in numbers:
# Append it to the list
numbers.append(rndnum)
return numbers
got stuck in a exercise and could need som help!
Exercise: Create a function that takes the list:
[123, 4, 125, 69, 155]
as argument. The function should multiply all even numbers by 1 and
add 6 to all odd numbers. Answer with the modified list sorted in
numerical order, descending.
my code so far is.
list1 = [123, 4, 125, 69, 155]
def multi():
for num in list1:
if num % 2 == 0:
num * 1
else:
num + 6
return list1
In the answer i put `def multi():
the answer i get is
[123, 4, 125, 69, 155] <class 'list'>
and the correct answer is [161,131,129,75,4]
could anyone please point me in the right way?
Thank you.
You are modify the for loop variable num itself and not the original list value
Code below should do the job
list1 = [123, 4, 125, 69, 155]
def multi():
for i,num in enumerate(list1):
if num % 2 == 0:
num *= 1
else:
num += 6
list1[i] = num # modify list value
return sorted(list1)[::-1] # this do sorting then reverse from large to small
No need to multiply by 1. just check if number is odd add 6.
list1 = [123, 4, 125, 69, 155]
def multi():
for i,num in enumerate(list1):
if num % 2 != 0:
num +=6
list1[i] = num
return sorted(list1)[::-1]
I need to complete this code for school.
The program should find an index of sequence split in the list.
For example for input which is a list like this
[66, 81, 83, 96, 13, 19, 30, 41, 44, 57]
the correct output should be 4 (index of number where the sequence is interrupted - 96)
My function is able to find the split but I don't know how to return an index of that split. It always return incorrect answer.
Here is my code:
def findSplit( list ):
if len(list)%2 == 0:
if list[(len(list)//2)-1] == list[0]:
return 1
elif list[(len(list)//2)-1]<list[0]:
return findSplit(list[:(len(list)//2)]) - len(list)//2
elif list[(len(list)//2)-1]>list[0]:
return findSplit(list[(len(list)//2)-1:]) + len(list)//2
elif len(list)%2 != 0:
if list[(len(list)//2)]<list[0]:
return findSplit(list[:(len(list)//2)+1]) - len(list)//2
elif list[(len(list)//2)]>list[0]:
return findSplit(list[(len(list)//2):]) + len(list)//2
if __name__ == "__main__":
list = [ 66, 81, 83, 96, 13, 19, 30, 41, 44, 57 ]
line = input().strip().split()
if line != []:
list = []
for x in line:
list.append( int( x ) )
print(findSplit( list ))
First and most importantly don't name any of your variables list as they overwrite the builtin function. I have changed the name to lst in my code below.
Your code is fine except for a small mistake, when ever you find out that the split is the first half, you need not subtract the length of the other half.
return findSplit(lst[:(len(list)//2)+1]) # THIS MUCH IS ENOUGH!
This is because you are returning the index in the first half, hence the indices start from this half itself. If you subtract you are going into the negative. In your particular case, you are subtracting 4 (the correct value) with 5 (the length of the other split) and hence you are getting the wrong answer -1 which is 4-5.
The edited code can be written as
def findSplit( lst ):
if len(lst)%2 == 0:
if lst[(len(lst)//2)-1] == lst[0]:
return 1
elif lst[(len(lst)//2)-1]<lst[0]:
return findSplit(lst[:(len(lst)//2)])
elif lst[(len(lst)//2)-1]>lst[0]:
return findSplit(lst[(len(lst)//2)-1:]) + len(lst)//2
elif len(lst)%2 != 0:
if lst[(len(lst)//2)]<lst[0]:
return findSplit(lst[:(len(lst)//2)+1])
elif lst[(len(lst)//2)]>lst[0]:
return findSplit(lst[(len(lst)//2):]) + len(lst)//2
Now when we print the output we get the correct value.
>>> findSplit([ 66, 81, 83, 96, 13, 19, 30, 41, 44, 57 ])
4
I don't understand the second part of your code though ;)
I have a list of integers which I need to parse into a string of ranges.
For example:
[0, 1, 2, 3] -> "0-3"
[0, 1, 2, 4, 8] -> "0-2,4,8"
And so on.
I'm still learning more pythonic ways of handling lists, and this one is a bit difficult for me. My latest thought was to create a list of lists which keeps track of paired numbers:
[ [0, 3], [4, 4], [5, 9], [20, 20] ]
I could then iterate across this structure, printing each sub-list as either a range, or a single value.
I don't like doing this in two iterations, but I can't seem to keep track of each number within each iteration. My thought would be to do something like this:
Here's my most recent attempt. It works, but I'm not fully satisfied; I keep thinking there's a more elegant solution which completely escapes me. The string-handling iteration isn't the nicest, I know -- it's pretty early in the morning for me :)
def createRangeString(zones):
rangeIdx = 0
ranges = [[zones[0], zones[0]]]
for zone in list(zones):
if ranges[rangeIdx][1] in (zone, zone-1):
ranges[rangeIdx][1] = zone
else:
ranges.append([zone, zone])
rangeIdx += 1
rangeStr = ""
for range in ranges:
if range[0] != range[1]:
rangeStr = "%s,%d-%d" % (rangeStr, range[0], range[1])
else:
rangeStr = "%s,%d" % (rangeStr, range[0])
return rangeStr[1:]
Is there a straightforward way I can merge this into a single iteration? What else could I do to make it more Pythonic?
>>> from itertools import count, groupby
>>> L=[1, 2, 3, 4, 6, 7, 8, 9, 12, 13, 19, 20, 22, 23, 40, 44]
>>> G=(list(x) for _,x in groupby(L, lambda x,c=count(): next(c)-x))
>>> print ",".join("-".join(map(str,(g[0],g[-1])[:len(g)])) for g in G)
1-4,6-9,12-13,19-20,22-23,40,44
The idea here is to pair each element with count(). Then the difference between the value and count() is constant for consecutive values. groupby() does the rest of the work
As Jeff suggests, an alternative to count() is to use enumerate(). This adds some extra cruft that needs to be stripped out in the print statement
G=(list(x) for _,x in groupby(enumerate(L), lambda (i,x):i-x))
print ",".join("-".join(map(str,(g[0][1],g[-1][1])[:len(g)])) for g in G)
Update: for the sample list given here, the version with enumerate runs about 5% slower than the version using count() on my computer
Whether this is pythonic is up for debate. But it is very compact. The real meat is in the Rangify() function. There's still room for improvement if you want efficiency or Pythonism.
def CreateRangeString(zones):
#assuming sorted and distinct
deltas = [a-b for a, b in zip(zones[1:], zones[:-1])]
deltas.append(-1)
def Rangify((b, p), (z, d)):
if p is not None:
if d == 1: return (b, p)
b.append('%d-%d'%(p,z))
return (b, None)
else:
if d == 1: return (b, z)
b.append(str(z))
return (b, None)
return ','.join(reduce(Rangify, zip(zones, deltas), ([], None))[0])
To describe the parameters:
deltas is the distance to the next value (inspired from an answer here on SO)
Rangify() does the reduction on these parameters
b - base or accumulator
p - previous start range
z - zone number
d - delta
To concatenate strings you should use ','.join. This removes the 2nd loop.
def createRangeString(zones):
rangeIdx = 0
ranges = [[zones[0], zones[0]]]
for zone in list(zones):
if ranges[rangeIdx][1] in (zone, zone-1):
ranges[rangeIdx][1] = zone
else:
ranges.append([zone, zone])
rangeIdx += 1
return ','.join(
map(
lambda p: '%s-%s'%tuple(p) if p[0] != p[1] else str(p[0]),
ranges
)
)
Although I prefer a more generic approach:
from itertools import groupby
# auxiliary functor to allow groupby to compare by adjacent elements.
class cmp_to_groupby_key(object):
def __init__(self, f):
self.f = f
self.uninitialized = True
def __call__(self, newv):
if self.uninitialized or not self.f(self.oldv, newv):
self.curkey = newv
self.uninitialized = False
self.oldv = newv
return self.curkey
# returns the first and last element of an iterable with O(1) memory.
def first_and_last(iterable):
first = next(iterable)
last = first
for i in iterable:
last = i
return (first, last)
# convert groups into list of range strings
def create_range_string_from_groups(groups):
for _, g in groups:
first, last = first_and_last(g)
if first != last:
yield "{0}-{1}".format(first, last)
else:
yield str(first)
def create_range_string(zones):
groups = groupby(zones, cmp_to_groupby_key(lambda a,b: b-a<=1))
return ','.join(create_range_string_from_groups(groups))
assert create_range_string([0,1,2,3]) == '0-3'
assert create_range_string([0, 1, 2, 4, 8]) == '0-2,4,8'
assert create_range_string([1,2,3,4,6,7,8,9,12,13,19,20,22,22,22,23,40,44]) == '1-4,6-9,12-13,19-20,22-23,40,44'
This is more verbose, mainly because I have used generic functions that I have and that are minor variations of itertools functions and recipes:
from itertools import tee, izip_longest
def pairwise_longest(iterable):
"variation of pairwise in http://docs.python.org/library/itertools.html#recipes"
a, b = tee(iterable)
next(b, None)
return izip_longest(a, b)
def takeuntil(predicate, iterable):
"""returns all elements before and including the one for which the predicate is true
variation of http://docs.python.org/library/itertools.html#itertools.takewhile"""
for x in iterable:
yield x
if predicate(x):
break
def get_range(it):
"gets a range from a pairwise iterator"
rng = list(takeuntil(lambda (a,b): (b is None) or (b-a>1), it))
if rng:
b, e = rng[0][0], rng[-1][0]
return "%d-%d" % (b,e) if b != e else "%d" % b
def create_ranges(zones):
it = pairwise_longest(zones)
return ",".join(iter(lambda:get_range(it),None))
k=[0,1,2,4,5,7,9,12,13,14,15]
print create_ranges(k) #0-2,4-5,7,9,12-15
def createRangeString(zones):
"""Create a string with integer ranges in the format of '%d-%d'
>>> createRangeString([0, 1, 2, 4, 8])
"0-2,4,8"
>>> createRangeString([1,2,3,4,6,7,8,9,12,13,19,20,22,22,22,23,40,44])
"1-4,6-9,12-13,19-20,22-23,40,44"
"""
buffer = []
try:
st = ed = zones[0]
for i in zones[1:]:
delta = i - ed
if delta == 1: ed = i
elif not (delta == 0):
buffer.append((st, ed))
st = ed = i
else: buffer.append((st, ed))
except IndexError:
pass
return ','.join(
"%d" % st if st==ed else "%d-%d" % (st, ed)
for st, ed in buffer)
Here is my solution. You need to keep track of various pieces of information while you iterate through the list and create the result - this screams generator to me. So here goes:
def rangeStr(start, end):
'''convert two integers into a range start-end, or a single value if they are the same'''
return str(start) if start == end else "%s-%s" %(start, end)
def makeRange(seq):
'''take a sequence of ints and return a sequence
of strings with the ranges
'''
# make sure that seq is an iterator
seq = iter(seq)
start = seq.next()
current = start
for val in seq:
current += 1
if val != current:
yield rangeStr(start, current-1)
start = current = val
# make sure the last range is included in the output
yield rangeStr(start, current)
def stringifyRanges(seq):
return ','.join(makeRange(seq))
>>> l = [1,2,3, 7,8,9, 11, 20,21,22,23]
>>> l2 = [1,2,3, 7,8,9, 11, 20,21,22,23, 30]
>>> stringifyRanges(l)
'1-3,7-9,11,20-23'
>>> stringifyRanges(l2)
'1-3,7-9,11,20-23,30'
My version will work correctly if given an empty list, which I think some of the others will not.
>>> stringifyRanges( [] )
''
makeRanges will work on any iterator that returns integers and lazily returns a sequence of strings so can be used on infinite sequences.
edit: I have updated the code to handle single numbers that are not part of a range.
edit2: refactored out rangeStr to remove duplication.
how about this mess...
def rangefy(mylist):
mylist, mystr, start = mylist + [None], "", 0
for i, v in enumerate(mylist[:-1]):
if mylist[i+1] != v + 1:
mystr += ["%d,"%v,"%d-%d,"%(start,v)][start!=v]
start = mylist[i+1]
return mystr[:-1]