How to speed the process time of a function that finds combinations? - python

I am working on this problem where I need to find all of the combinations of the purchase items in a .csv file that equal a total. The purchase items can be positive and negative. When I run my code with practice data I can get the correct answer but when I use the real data which has hundreds of purchases it runs forever. I am wondering how to speed up the processing time of the following code.
import decimal
import pandas
import datetime
df = pandas.read_csv('negative_test.csv')
print(df)
# Index are the keys of the dictonary
index_list = list(df.index)
# Values are the values of the dictonary
values = df["Purchase"].to_list()
target = df["Target"].to_list()[0]
print(target)
def sanitize_values(list1):
sanitized_list = []
for item in list1:
sanitized_list.append(float(item.replace(",","")))
return sanitized_list
def merge(list1, list2):
merged_list = [(list1[i], list2[i]) for i in range(0, len(list1))]
return merged_list
merged_tuples = merge(index_list,sanitize_values(values))
def sum_tuples(tuples):
s = 0
for i in range(len(tuples)):
s += tuples[i][1]
#s += round(tuples[i][1],2)
return s
def subset_sum(numbers, target, partial=[], s=0, progress=0):
if(len(partial) > 0):
s += partial[len(partial)-1][1]
#s = sum_tuples(partial)
# check if the partial sum is equals to target
if round(s,2) == round(target,2):
print ((partial, target))
if len(numbers) == 0:
return
for i in range(len(numbers)):
#hacked in progress bar
if(len(partial) == 0):
progress += 1
printDateTime()
print("progress: " + str(progress))
#print("Starting from: " + str(i) + " Numbers: " + str(numbers) + "\n len: " + str(len(partial)) + "partial: " + str(partial))
n = numbers[i][1]
#n = round(numbers[i][1],2)
remaining = numbers[i+1:]
# print(remaining)
subset_sum(remaining, target, partial + [numbers[i]], s, progress)
def printDateTime():
now = datetime.datetime.now()
print ("Current date and time : ")
print (now.strftime("%Y-%m-%d %H:%M:%S"))
if __name__ == "__main__":
printDateTime()
subset_sum(merged_tuples,target)
printDateTime()

Related

Implementing a match counter into a lotto number guesser

im rather new to python and found someones lottery simulation in github. After playing around with it for a while i wanted to add a counter, that counts the number of matches of your Number out of the total draws.
I don't know if it is because i did not write the code myself, but i can't seem to make it happen. I've tried some of pythons counter modules bu that did'nt seem to be the right thing.
Heres my code:
import random
import time
### TODO - Refactor GetDrawNumbers (add timers)
### TODO - Refactor CheckNumbers
def GetDrawNumbers():
drawNumbers = []
for i in range(6):
x = None
while (x == None or x in drawNumbers):
x = random.randint(1, 49)
drawNumbers.append(x)
return drawNumbers
def CheckNumbers(myTicket, actualNumbers):
numbersMatched = 0
for number in myTicket:
if number in actualNumbers:
numbersMatched += 1
return numbersMatched
### Script starts here
startTime = time.perf_counter()
myNumbers = [4, 8, 15, 16, 23, 42]
for draw in range(2000):
drawNumber = draw + 1
thisWeeksDraw = GetDrawNumbers()
numbersMatched = CheckNumbers(myNumbers, thisWeeksDraw)
##print("Week " + str(drawNumber) + " numbers : " + str(thisWeeksDraw) + " (" + str(numbersMatched) + " matched)")
if numbersMatched == 4:
print("Week " + str(drawNumber) + " numbers : " + str(thisWeeksDraw) + " (" + str(numbersMatched) + " matched)")
count = numbersMatched
print("Total matches: " + str(count))
endTime = time.perf_counter()
elapsedTime = endTime - startTime
print("Completed in " + str(elapsedTime) + " seconds!")
If anyone knows a way to implement a counter, that counts the number of times this the program gets 3,4,5 or 6 correct matches i would be super relieved! It's not that this project would be super important but solving the problem would be a milestone for me and my learning process!
Thanks in advance and best wishes!
How about this where I have added a check of the numbersMatched value and increment a counter whenever it is 3 or more
import random
import time
### TODO - Refactor GetDrawNumbers (add timers)
### TODO - Refactor CheckNumbers
def GetDrawNumbers():
drawNumbers = []
for i in range(6):
x = None
while (x == None or x in drawNumbers):
x = random.randint(1, 49)
drawNumbers.append(x)
return drawNumbers
def CheckNumbers(myTicket, actualNumbers):
numbersMatched = 0
for number in myTicket:
if number in actualNumbers:
numbersMatched += 1
return numbersMatched
### Script starts here
startTime = time.perf_counter()
myNumbers = [4, 8, 15, 16, 23, 42]
countOfThreeOrMoreMatched = 0
for draw in range(2000):
drawNumber = draw + 1
thisWeeksDraw = GetDrawNumbers()
numbersMatched = CheckNumbers(myNumbers, thisWeeksDraw)
##print("Week " + str(drawNumber) + " numbers : " + str(thisWeeksDraw) + " (" + str(numbersMatched) + " matched)")
if numbersMatched >= 3:
countOfThreeOrMoreMatched += 1
if numbersMatched == 4:
print("Week " + str(drawNumber) + " numbers : " + str(thisWeeksDraw) + " (" + str(numbersMatched) + " matched)")
print(f"Count with 3 or more matches {countOfThreeOrMoreMatched}")
count = numbersMatched
print("Total matches: " + str(count))
endTime = time.perf_counter()
elapsedTime = endTime - startTime
print("Completed in " + str(elapsedTime) + " seconds!")

python program way to check for type in Python?

def main():
a,b=numbers(5,1,100)
print("Number of Odd values = " + str(a))
print("Number of Even values = " + str(b))
def numbers(N,A,B):
even_count,odd_count=0,0
for i in range(N):
n=random.randint(A,B)
if n%2==0:
even_count+=1
else:
odd_count+=1
return odd_count, even_count
main()
Need fix this code.i don't know when the number can't go through.
print("Number of Odd values = " + str(a))
NameError: name 'a' is not defined
Try this:
import random
def numbers(N,A,B):
even_count,odd_count=0,0
for i in range(N):
n=random.randint(A,B)
if n%2==0:
even_count+=1
else:
odd_count+=1
return odd_count, even_count
a,b=numbers(5,1,100)
print("Number of Odd values = " + str(a))
print("Number of Even values = " + str(b))
you need to make sure the print statements are coming inside the scope of function main()
and import module random at the top of the script. below is the formatted version.
def main():
a,b=numbers(5,1,100)
print("Number of Odd values = " + str(a))
print("Number of Even values = " + str(b))
def numbers(N,A,B):
even_count,odd_count=0,0
for i in range(N):
n=random.randint(A,B)
if n%2==0:
even_count+=1
else:
odd_count+=1
return odd_count, even_count
main()
I guess you need you to reorder the code,try this:
import random
def numbers(N,A,B):
even_count, odd_count = 0, 0
for i in range(N):
n = random.randint(A, B)
if n % 2 == 0:
even_count += 1
else:
odd_count += 1
return odd_count, even_count
def main():
a, b = numbers(5, 1, 100)
print("Number of Odd values = " + str(a))
print("Number of Even values = " + str(b))
main()

python3 recursive function of n * (b(a))

I'm trying to write a function that would recursively hash a key for n times, alternating between sha224 and sha256. Each iteration would be hash_256(hash_224)--a hash256 for the hash224 of the key--so that it would yield n * (hash_256(hash_224)). However, I'm new to coding and can't figure out how to write a recursive function with these parameters.
import hashlib
def shasum(key, n):
key = str(key).encode('utf-8')
hash_a = hashlib.sha224(key).hexdigest().encode('utf-8'))
hash_b = hashlib.sha256(hash_a).hexdigest()
if n == 0 or 1:
return hash_b #one iteration of 256(224)
else:
return n-1
return hash_b #stuck here
Edited: now it behaves like a number generator. What's wrong?
import hashlib
n = 0
def sha480(seed):
hashed_224 = str(hashlib.sha224(seed)).encode('utf-8')
hashed_256 = hashlib.sha256(hashed_224).hexdigest()
hashed_480 = str(hashed_256)
print("hash: " + hashed_480)
def repeater(key, n):
if n == 0:
return key
seed = str(key).encode('utf-8')
while n > 0:
return sha480(repeater(seed, n-1))
repeater('what', 2)
You have no recursive calls at all. You could change it to:
def hash_a(key):
return hashlib.sha224(key).hexdigest().encode('utf-8')
def hash_b(key):
return hashlib.sha256(key).hexdigest()
def shasum(key, n):
if n == 0: # base case: 0 iterations -> return key itself
return key
key = str(key).encode('utf-8')
return hash_b(hash_a(shasum(key, n - 1))) # recursve call
A side note: n == 0 or 1 is equivalent to (n == 0) or 1 which is always true. For that pattern, use n == 0 or n == 1 or shorter n in (0, 1)
Your code is nearly correct. just some minor issues fixed as below
import hashlib
def shasum(key, n):
print ("n: " + str(n))
key = str(key).encode('utf-8')
hash_a = hashlib.sha224(key).hexdigest().encode('utf-8')
print ("hash_a: " + str(hash_a))
hash_b = hashlib.sha256(hash_a).hexdigest()
print ("hash_b: " + str(hash_b))
if n == 0:
return hash_b #one iteration of 256(224)
else:
return shasum(hash_b, n-1)

string index out of range list iteration

I am fairly new to python, I am not sure on how to fix a index string out of range. it happens right after the while loop when I want to send mylist[i][0] to formatting function. Any pointer on my code in general would be awesome!
def formatting(str1):
if str1 == '?':
return True
else:
return False
while(i <= len(mylist)):
val = formatting(mylist[i][0])
if val == True:
str1 = mylist[i]
str2 = mylist[i+1]
i = i + 2
format_set(str1, str2)
else:
if format == True:
if (margin + count + len(mylist[i])) <= width:
if (i == (len(mylist)-1)):
list2.append(mylist[i])
print(" " * margin + " ".join(list2))
break
list2.append(mylist[i])
count += len(mylist[i])
i += 1
else:
print(" " * margin + " ".join(list2))
list2 = []
count = 0
else:
temp_margin = margin
temp_width = width
width = 60
margin = 0
if (margin + count + len(mylist[i])) <= width:
if (i == (len(mylist)-1)):
list2.append(mylist[i])
print(" " * margin + " ".join(list2))
margin = temp_margin
width = temp_width
break
list2.append(mylist[i])
count += len(mylist[i])
i += 1
else:
print(" " * margin + " ".join(list2))
list2 = []
count = 0
change
i <= len(mylist)
to
i < len(mylist)
In the last iteration of the while loop, i is referring to the last value. Hence,
str2 = mylist[i+1]
is trying to reference a string outside the allowed range and you get an error.
EDIT: Also, as Wcrousse mentioned, the while (i <= len(...)) should be changed to i < len(...) because indexes go from 0 - (length-1).

To print the lists for the code?

sub = [767220, 769287, 770167, 770276, 770791, 770835, 771926, 1196500, 1199789,1201485, 1206331, 1206467, 1210929, 1213184, 1213204, 1213221, 1361867, 1361921, 1361949, 1364886, 1367224, 1368005, 1368456, 1368982, 1369000, 1370365, 1370434, 1370551, 1371492, 1471407, 1709408, 1710264, 1710308, 1710322, 1710350, 1710365, 1710375]
def runningMean(seq, n=0, total=0): #function called recursively
if not seq:
return []
total = total + int(seq[-1])
if int(seq[-1]) < total/float(n+1) * 0.9: # Check your condition to see if it's time to stop averaging.
return []
return runningMean(seq[:-1], n=n+1, total=total) + [total/float(n+1)]
avg = runningMean(sub, n = 0, total = 0)
print avg #it prints the avg value which satisfies the above condition
The result obtain is:
[1710198.857142857, 1710330.6666666667, 1710344.0, 1710353.0, 1710363.3333333333, 1710370.0, 1710375.0]
but now I need to print both the average & sub list which satisfies the condition(the items in list sub that are greater than the items in avg so it prints avg now I need it to print the items in seq also)
i.e.
[1710198.857142857, 1710330.6666666667, 1710344.0, 1710353.0, 1710363.3333333333, 1710370.0, 1710375.0]
[1709408, 1710264, 1710308, 1710322, 1710350, 1710365, 1710375]
How I can change the code which will provide me such a result in Python?
Try this:
sub = [767220, 769287, 770167, 770276, 770791, 770835, 771926, 1196500, 1199789,1201485, 1206331, 1206467, 1210929, 1213184, 1213204, 1213221, 1361867, 1361921, 1361949, 1364886, 1367224, 1368005, 1368456, 1368982, 1369000, 1370365, 1370434, 1370551, 1371492, 1471407, 1709408, 1710264, 1710308, 1710322, 1710350, 1710365, 1710375]
def runningMean(seq, n=0, total=0): #function called recursively
L = [[],[]]
if len(seq) == 0:
return L
total = total + int(seq[-1])
if int(seq[-1]) < total/float(n+1) * 0.9: # Check your condition to see if it's time to stop averaging.
return L
NL = runningMean(seq[:-1], n=n+1, total=total)
L[0] += NL[0] + [total/float(n+1)]
L[1] += [seq[-1]] + NL[1]
return L
avg = runningMean(sub, 0, 0)
print(avg[0])
print(avg[1])
Output:
[1710198.857142857, 1710330.6666666667, 1710344.0, 1710353.0, 1710363.3333333333, 1710370.0, 1710375.0]
[1710375, 1710365, 1710350, 1710322, 1710308, 1710264, 1709408]
Python can return multiple values from a method. You can use this to return on each call the elements that you are interested in.

Categories