I am supposed to write a function for one of my computer science classes in python. The function is supposed to take in a startValue and then increment it until numberOfValues is reached. This is my function so far:
def nextNValues(startValue, increment, numberOfValues):
result = int(0)
for i in range(0, numberOfValues):
increase = i * increment
result = startValue + increase
return result
I call it by doing:
print(nextNValues(5,4,3))
The problem is that the output is only 13. How do I make it so it returns a number each time it increments. For example, 5, 9, 13? I have been having this problem with my previous functions but I have just been adding and removing things without much logic to get it to work. What am I doing wrong?
This is a perfect use case for generators.
Long story short, just use yield instead of return:
def nextNValues(startValue, increment, numberOfValues):
result = int(0)
for i in range(0, numberOfValues):
increase = i * increment
result = startValue + increase
yield result
The clients of your code can then use it either in a simple loop:
for value in nextNValues(...):
print(value)
Or they can get a list if needed by converting it with list.
For example, if one needed to print the result:
print(list(nextNValues(...)))
You should build up a list. Each time through the iteration, append the number to the list. Then, at the end, simply return the list.
def nextNValues(startValue, increment, numberOfValues):
result = []
for i in range(0, numberOfValues):
increase = i * increment
#result = startValue + increase
result.append(startValue + increase)
return result
Related
This is for a school assignment.
I have been tasked to define a function determining the largest square pyramidal number up to a given integer(argument). For some background, these are square pyramidal numbers:
1 = 1^2
5 = 1^2+2^2
14 = 1^2+2^2+3^2
So for a function and parameter largest_square_pyramidal_num(15), the function should return 14, because that's the largest number within the domain of the argument.
I get the idea. And here's my code:
def largest_square_pyramidal_num(n):
sum = 0
i = 0
while sum < n:
sum += i**2
i += 1
return sum
Logically to me, it seemed nice and rosy until I realised it doesn't stop when it's supposed to. When n = 15, sum = 14, sum < n, so the code adds one more round of i**2, and n is exceeded. I've been cracking my head over how to stop the iteration before the condition sum < n turns false, including an attempt at break and continue:
def largest_square_pyramidal_num(n):
sum = 0
for i in range(n+1):
sum += i**2
if sum >= n:
break
else:
continue
return sum
Only to realise it doesn't make any difference.
Can someone give me any advice? Where is my logical lapse? Greatly appreciated!
You can do the following:
def largest_pyr(x):
pyr=[sum([i**2 for i in range(1,k+1)]) for k in range(int(x**0.5)+1)]
pyr=[i for i in pyr if i<=x]
return pyr[-1]
>>>largest_pyr(15)
14
>>> largest_pyr(150)
140
>>> largest_pyr(1500)
1496
>>> largest_pyr(15000)
14910
>>> largest_pyr(150000)
149226
Let me start by saying that continue in the second code piece is redundant. This instruction is used for scenario when you don't want the code in for loop to continue but rather to start a new iteration (in your case there are not more instructions in the loop body).
For example, let's print every number from 1 to 100, but skip those ending with 0:
for i in range(1, 100 + 1):
if i % 10 != 0:
print(i)
for i in range(1, 100 + 1):
if i % 10 == 0:
# i don't want to continue executing the body of for loop,
# get me to the next iteration
continue
print(i)
The first example is to accept all "good" numbers while the second is rather to exclude the "bad" numbers. IMHO, continue is a good way to get rid of some "unnecessary" elements in the container rather than writing an if (your code inside if becomes extra-indented, which worsens readability for bigger functions).
As for your first piece, let's think about it for a while. You while loop terminates when the piramid number is greater or equal than n. And that is not what you really want (yes, you may end up with a piramid number which is equal to n, but it is not always the case).
What I like to suggest is to generate a pyramid number until in exceedes n and then take a step back by removing an extra term:
def largest_square_pyramidal_num(n):
result = 0
i = 0
while result <= n:
i += 1
result += i**2
result -= i ** 2
return result
2 things to note:
don't use sum as a name for the variable (it might confuse people with built-in sum() function)
I swapped increment and result updating in the loop body (such that i is up-to-date when the while loop terminates)
So the function reads like this: keep adding terms until we take too much and go 1 step back.
Hope that makes some sense.
Cheers :)
I am trying to solve assignment problem, the code I wrote takes extremely long to run. I think it's due to nested loop I used. Is there another way to rewrite the code to make it more efficient.
The question I am trying to solve. Basically, starting at first element to compare with every element to its right. if it is larger than the rest, it will be "dominator". Then the second element to compare with every element to its right again. All the way to the last element which will be automatically become "dominator"
def count_dominators(items):
if len(items) ==0:
return len(items)
else:
k = 1
for i in range(1,len(items)):
for j in items[i:]:
if items[i-1]>j:
k = k+1
else:
k = k+0
return k
You can use a list comprehension to check if each item is a "dominator", then take the length - you have to exclude the final one to avoid taking max of an empty list, then we add 1 because we know that the final one is actually a dominator.
num_dominators = len([i for i in range(len(items) - 1) if items[i] > max(items[i + 1:])]) + 1
This is nice because it fits on one line, but the more efficient (single pass through the list) way to do it is to start at the end and every time we find a new number bigger than any we have seen before, count it:
biggest = items[-1]
n = 1
for x in reversed(items):
if x > biggest:
biggest = x
n+=1
return n
Currently taking a programming course and got as an assignment to find the first fibonacci number above a million and I'm having a bit of trouble finding the specific number. I'm also supposed to be finding the index of the n:th number when it hits 1 million. I'm pretty new to coding but this is what I've come up with so far, just having a hard time to figure out how to actually calculate what the number is.
I guess you would switch out the for-with a while-loop but haven't figured out it how to get it all to work.
Thanks in beforehand :)
def fib_seq(n):
if n <= 2:
return 1
return fib_seq(n-1) + fib_seq(n-2)
lst = []
for i in range(1, 20):
lst.append(i)
print(fib_seq(i), lst)
Some points:
You don't need to build a list. You're only asked to return an index and the corresponding Fibonnacci number.
The recursive algorithm for Fibonnacci is not best practice, unless you would use some memoization. Otherwise the same numbers have to be recalculated over and over again. Use an iterative method instead.
Here is how that could look:
def fib(atleast):
a = 0
b = 1
i = 1
while b < atleast:
a, b = b, a+b
i += 1
return i, b
print(fib(1000000)) # (31, 1346269)
If you need to do this with some find of recursion, you should try to avoid calling the recursions twice with each iteration. This is a classic example where the complexity explodes. One way to do this is to memoize the already calculated results. Another is to maintain state with the function arguments. For example this will deliver the answer and only call the function 32 times:
def findIndex(v, prev = 0, current = 1, index = 0):
if v < prev:
return (prev, index)
return findIndex(v, current, prev+current, index + 1 )
findIndex(1000000) # (1346269, 31)
Alright, I wrote the following code to find the union of any number of probabilities (wonderful article on the topic here: https://www.thoughtco.com/probability-union-of-three-sets-more-3126263):
#Finds all Intersections
def intersection_finder1(poss, intersection_number):
#Make Lists of descending possibilities intersection_number times, Works for 2, not 3
sub_posses = []
use = poss
sub_posses.append(use)
for i in range(intersection_number - 1):
#print use[(i+1):], intersection_number
sub_posses.append(use[(i+1):])
return sub_posses
def sub_poss_modifier(sub_posses):
for x in range(len(sub_posses)):
del sub_posses[x][0]
return sub_posses
def intersection_finder2(sub_posses, intersection_number, ongoing_sum=0):
#Iterate over lists for list_item_number_1
#Increment lists by one
#Repeat for last_list length times,
#Commented out below are debugging things
multi = 1
for y in range(len(sub_posses[-1])):
for i in range(len(sub_posses)):
multi = multi * sub_posses[i][y]
#print multi, sub_posses[i][y], intersection_number
#print "-----------RESTART------------"
ongoing_sum += multi
multi = 1
if len(sub_posses[-1]) > 1:
new_lt = sub_poss_modifier(sub_posses)
return intersection_finder2(new_lt, intersection_number, ongoing_sum)
return ongoing_sum
def combiner(poss):
#Sums Possbilities
total = sum(poss)
ongoing_total = total
#Adds/Subtracts Combinations
for i in range(2, len(poss) + 1):
#Somehow, poss is changing. I have no idea how.
#Say poss is [1/2.0, 1/2.0, 1/2.0]. If you put that in, the function works. If you put poss in, it doesn't
print poss
sub_poss = intersection_finder1(poss, i)
aors = intersection_finder2(sub_poss, i)
#print aors, i
if i % 2 == 0:
ongoing_total -= aors
else:
ongoing_total += aors
#Returns total Possbility
return ongoing_total
print combiner([1/2.0, 1/2.0, 1/2.0])
It works but only if I make a specific change in which the value of the variable poss is inserted in place of itself. For Example (the only change is in the 9th line of combiner):
#Finds all Intersections
def intersection_finder1(poss, intersection_number):
#Make Lists of descending possibilities intersection_number times, Works for 2, not 3
sub_posses = []
use = poss
sub_posses.append(use)
for i in range(intersection_number - 1):
#print use[(i+1):], intersection_number
sub_posses.append(use[(i+1):])
return sub_posses
def sub_poss_modifier(sub_posses):
for x in range(len(sub_posses)):
del sub_posses[x][0]
return sub_posses
def intersection_finder2(sub_posses, intersection_number, ongoing_sum=0):
#Iterate over lists for list_item_number_1
#Increment lists by one
#Repeat for last_list length times,
#Commented out below are debugging things
multi = 1
for y in range(len(sub_posses[-1])):
for i in range(len(sub_posses)):
multi = multi * sub_posses[i][y]
#print multi, sub_posses[i][y], intersection_number
#print "-----------RESTART------------"
ongoing_sum += multi
multi = 1
if len(sub_posses[-1]) > 1:
new_lt = sub_poss_modifier(sub_posses)
return intersection_finder2(new_lt, intersection_number, ongoing_sum)
return ongoing_sum
def combiner(poss):
#Sums Possbilities
total = sum(poss)
ongoing_total = total
#Adds/Subtracts Combinations
for i in range(2, len(poss) + 1):
#Somehow, poss is changing. I have no idea how.
#Say poss is [1/2.0, 1/2.0, 1/2.0]. If you put that in, the function works. If you put poss in, it doesn't
#print poss
sub_poss = intersection_finder1([1/2.0, 1/2.0, 1/2.0], i)
aors = intersection_finder2(sub_poss, i)
#print aors, i
if i % 2 == 0:
ongoing_total -= aors
else:
ongoing_total += aors
#Returns total Possbility
return ongoing_total
print combiner([1/2.0, 1/2.0, 1/2.0])
By doing a little debugging, I found that the variable poss changes throughout each iteration of the for loop -- thus yielding an incorrect answer. Furthermore, it only changes in code block #1; in code block #2, poss stays the same. So far, I haven't been able to find any instance where I redefine or alter poss in any function. Also, even if I did alter poss somewhere, the only difference between code block #1 and #2 is the list in the ninth line of the function combiner. Yet, block #2 yields the correct answer, while block #1 doesn't.
The Terminal Output from block #1 (printing poss):
[0.5, 0.5, 0.5]
[0.5, 0.5]
0.75
The Terminal Output from block #2 (printing poss):
[0.5, 0.5, 0.5]
[0.5, 0.5, 0.5]
0.875
So far, to prevent poss from changing, while maintaining some level of general use, I've tried to redefine it and rename it. What can I do to stop poss from changing, while making it calculate different probabilities as simple as changing a variable?
By the way, I fairly new to programming, so any advice to make my code better or myself a better programmer as a whole would be greatly appreciated.
"So far, I haven't been able to find any instance where I redefine or
alter poss in any function."
You alter the objects referred to by your function parameter posse quite clearly. You essentially pass the result of intersection_finder1 to intersection_finder2 (apt names...) In intersection_finder1, you append posse to sub_posses. In other words, in the partitions of the set, you use the object itself to represent the improper subset.
def intersection_finder1(poss, intersection_number):
#Make Lists of descending possibilities intersection_number times, Works for 2, not 3
sub_posses = []
use = poss # NOT MAKING A COPY
This says the object referred to by posse is now also referred to by use
sub_posses.append(use) # now sub_posses includes posse
for i in range(intersection_number - 1):
#print use[(i+1):], intersection_number
sub_posses.append(use[(i+1):])
return sub_posses
Now, in intersection_finder2 you call sub_poss_modifier on sub_posses:
def sub_poss_modifier(sub_posses):
for x in range(len(sub_posses)):
del sub_posses[x][0]
return sub_posses
Where you clearly modify sub_posses[0], which will be posse
The solution? Make copies. You an use the built-in list method posse.copy(), or the well-understood python copy-idiom, poss[:].
def intersection_finder1(poss, intersection_number):
#Make Lists of descending possibilities intersection_number times, Works for 2, not 3
sub_posses = []
use = poss.copy()
And everywhere else where you don't want to share objects, but want a list of the same values...
Note
To get a better grip of how Python variables and values work, I suggest reading all of Ned Batchelder's Facts and myths about Python names and values.
Also you should know that these operations produce shallow copies. If you have more complicated data-structures than a list of immutable objects, say, a list of lists, or a list of dicts, you may need a deep-copy instead. You should know the difference.
When you are passing a list, it is passed as an object, not as a copy, and any assignment will refer to the object as reference.
You are appending poss to sub_posses in intersection_finder1(). This appends poss through its reference, not a copy, even if assigned to use.
In sub_poss_modifier() you delete some elements of sub_posses. This actually deletes the elements of poss too.
Solution is to make a copy when appending to sub_posses in intersection_finder1():
sub_posses.append(use[:])
I am trying to save the results of 10 function calls into a list. however, when I want to access this numerical data, I keep getting type errors, because the list is really a list of function calls. How do I make it do stuff so I can have numbers to do compare?
I tried setting temp variable to result of each spot in the list, but it still shows as a function.
Output should show the average for different # of dice, and return the best amount of dice to roll
def calculator(fn, num_samples=1000): # this is the function I'm trying to call
def print_and_return(*args):
total3 = 0
for _ in range(num_samples):
total3 += (fn(*args))
return float(total3)/num_samples
return print_and_return
def find_average(dice=six_sided):
avglist = []
k, spot = 0, 0
bob = roll_dice(k+1, dice)
passed_function = calculator(bob, 1000)
print(passed_function)
while k <= 10:
avglist.append((passed_function)) # <==trying to save the results when I check with 1-10 dice rolls
if k == 0:
spot = 1
else:
temp = 0
max = 0
i = 0
while i <= len(avglist):
temp = avglist[i]
if max > temp:
max = temp
i +=1
if (avglist[k] > temp):
spot = k
print(k, "dice scores", avglist[k], "on average")
k +=1
return spot
You are not calling passed_function. Calling a function with no arguments still reqires the ().
Your calculator function returns a function, not a plain value. You therefore need to call passed_function in order to get your result.
Based on the arguments to your call to roll_dice, it looks like you want the k argument to vary in the loop. As written now, it will not. I suspect you are tripping yourself up a bit. The code could be written a whole lot simpler without so many function references being passed around.