Python: yield vs print in a loop - python

I am a beginner in Python currently working through Project Euler's problems (here for those who have not heard about it). I have solved this particular problem, however it leaves me with some questions:
def fibsum():
result = []
a, b = 0, 1
while True:
a, b = b, a + b
print b
if b < 4000000 and b % 2 == 0:
result.append(b)
if b > 4000000:
break
print sum(result)
fibsum()
When I run this using PowerShell, first it prints out all the numbers I need (although, it goes one over), and then finally prints the sum:
1
2
3
5
8
...
3524578
5702887 <-- This is over 4,000,000. Why is this here?
4613732 <-- This is the answer.
Is there any way that I can have the loop stop iterating before it reaches the first value over 4,000,000?
For the sake of saving space, is there any way that I can have all of the values print out in a list format ([ , , , ]), if I decide to use print?
When I replace print in the original code with yield or return(for the variable b), the program won't print anything out, despite there still being
print sum(result)
at the end of the function.
Is there any way that I can make this easier, without having to define result and appending values to it? When the values are returned in a format similar to the actual outcome, sum() doesn't seem to work.

1.Just move the 2nd condition before you print b:
while True:
a, b = b, a + b
if b > 4000000:
break
print b
if b < 4000000 and b % 2 == 0:
result.append(b)
2.Don't print b in loop, rather print the result once you break out.
3.Well, as for return, it's pretty clear that you return out of function, so the following code in function is not executed and hence your list is not populated.
yield is used to create a generator function, where every execution of your function returns the next value. So, you would have to call your function multiple times, thus adding the yielded value to a list defined outside. And when there is nothing to return, your function will break.
To understand yield keyword usage more clearly, take a look at this post: What does the "yield" keyword do in Python?
You can edit your code to use yield like this (haven't tested it):
def fibsum():
a, b = 0, 1
while True:
a, b = b, a + b
if b > 4000000:
break
yield b
result = []
for val in fibsum():
if val < 4000000 and val % 2 == 0:
result.append(val)
print sum(result)
So, in for loop, each call to fibsum() function generates the next value, which you add in the list, based on the condition.

Related

How to optimise the program to solve RecursionError: maximum recursion

The aim of this program is to find all the integer pairs of three that are in range of 0 and 57 that can form a triangle. (I made the program for a Math problem)
import random
import time
dict = {}
current_list = []
key_num = 0
def main():
global key_num
a = random.randint(1, 57)
b = random.randint(1, 57)
c = random.randint(1, 57)
if a + b > c and a + c > b and b + c > a:
current_list.append(a)
current_list.append(b)
current_list.append(c)
current_list.sort()
for i in range(0, key_num):
if dict[i] == current_list:
main()
dict.setdefault(key_num, current_list)
key_num += 1
current_list.clear()
print(str(key_num))
print(dict)
time.sleep(0.8)
while True:
main()
However, when I run it, there are two problems.
First, after a while program is launched, an error RecursionError: maximum recursion is displayed. For this, I have tried to set the limit higher to 10^5 but the program just crashed after a while.
Second, the dictionary isn't inputting any new items during the process.
I am not that experienced in python and thanks a lot if you would like to help.
Also, a + b > c and a + c > b and b + c > a is the criteria for an triangle: the sum of any two sides is bigger than the third side.
Ok, so first of all, in general stack overflow questions should be condensed to the point that their answers can be useful to others.
Now, there are several problem with your code:
you call main inside main. When you say:
if dict[i] == current_list:
main()
what I think you mean is: if this set of integers has already been checked, go back to the beginning. But instead it runs the function main() again, this time inside of itself. What you should do instead is write:
if dict[i] == current_list:
return
You don't have an end condition. The code won't stop because there is no way for it to exit the loop. You need some way to determine when it is finished.
dict.setdefault(key_num, current_list) has several issues. Number one is that the way you assign an item to a dictionary is: dict[key_num] = current_list. setdefault is a totally different thing and, while it somtimes produces the same result, it isn't the thing you are looking for.
The next issue is that you clear current_list in the next line, which means the list that you just put into your dictionary is now an empty list.
My recommendation is to restructure the code into several for loops to check every combination:
identifiedSets = [];
for a in range(1, 57):
for b in range(1, 57):
for c in range(1, 57):
if a + b > c and a + c > b and b + c > a:
newList = [a, b, c]
newList.sort();
identifiedSets.append(str(newList))
print(str(identifiedSets))
This way you will iterate through every possible combination of numbers and, by storing the results as a list of strings, you can check if those strings have already been added to the list. Finally, printing the results is easy because the results are already strings.

My python recursive function won't return and exceeds maximum recursive depth

I simply do not understand why this is not returning the value and stopping the recursion. I have tried everything but it seems to just keep on going no matter what I do. I am trying to get the program to get the loop to compare the first two values of the list if they are the same return that it was the first value. If they were not, add the first and second values of each list and compare, etc etc until it reaches the end of the list. If the sum of the values in each list never equal each other at any point then return 0.
It is supposed to take three inputs:
A single integer defining the length of the next two inputs
First set of input data
Second set of input data
Ex input
3
1 3 3
2 2 2
It should output a single number. In the case of the example data, it should output 2 because the sum of the lists equalled at the second value.
N = int(input())
s1 = input().split()
s2 = input().split()
count = 0
def func1(x,y):
if x == y:
return(count)
elif (N - 1) == count:
return(0)
else:
count + 1
return(func1(x + int(s1[count]), y + int(s2[count])))
days = func1(int(s1[0]),int(s2[0]))
print(days)
I am sorry in advance if I really messed up the formatting or made some dumb mistake, I am pretty new to programming and I have never posted on here before. Thanks in advance :)
The problem is that you never actually update the variable count. However, just writing:
count += 1
is not going to work either without declaring the variable global:
def func1(x, y):
global count
....
That said, global variables increase code complexity and break re-enterability, i.e. the same function can no longer be called twice, not to mention about concurrency. A much cleaner way is to make count a function argument, it will look like this (the code not tested and is here for illustration only):
N = int(input())
s1 = [int(c) for c in input().split()]
s2 = [int(c) for c in input().split()]
def func1(x, y, count=0):
if x == y:
return count
elif count == N - 1:
return 0
else:
return(func1(x + s1[count], y + s2[count]), count + 1)
days = func1(int(s1[0]),int(s2[0]))
print(days)
To answer "How would you go about solving this problem then" – If I understood the problem correctly, the aim is to find the index where the "running total" of the two lists is the same. If so,
def func1(s1, s2):
total_a = 0
total_b = 0
for i, (a, b) in enumerate(zip(s1, s2)):
total_a += a
total_b += b
if total_a == total_b:
return i
return 0
print(func1([1, 3, 3], [2, 2, 2]))
does the trick. (I've elided the input bits here – this function just works with two lists of integers.)

Difference between defining multiple variable at a time and individually

I am a newbie in Python and I'm trying to learn Python through self-learning. I was trying to build Fibonacci series using a while loop. Here is my code, which doesn't return the desired result. Could anyone explain the problem?
a = 0
b = 1
while b<100:
print(b)
a = b
b = a + b
If we define a, b simultaneously like a, b = b, a+b, this works perfectly. Why is this happening? I don't understand because in both cases I am defining a and b the same way.
This is because programming languages like Python, and many others, execute the statements you write in the order you write them.
This means that by the time you execute b = a + b, the value of a has already changed in the previous line.
An easy way to solve this would be using a third variable to store the results temporarily.
a = 0
b = 1
c = 1
while c < 100:
print(c)
c = a + b
a = b
b = c
You are making one small mistake.
When you do a = b, you are changing the value of a. After this, when you do b=a+b, it is actually equivalent to b = b+b => b=2b.
To avoid this, use a temporary variable temp and storethe value of a in it. Then change the value of a using a = b. Then do, a = a+b.
Following is the code:
a=0
b=1
while b<100:
print(b)
temp = a
a = b
b = temp+b
When you do a, b = b, a+b, the previous value of a is used for calculating the new b, we have don a similar thing above by storing the previous value of a in temp
Operator "comma" (,) in Python is used to create a tuple, and it is allowed to omit the parentheses that surround a tuple. The expression a, b = b, a+b is actually an assignment of one tuple to another:
(a, b) = (b, a + b)
This statement is executed by evaluating the tuple constructor on the right-hand side (b, a + b). At this point, a new anonymous tuple (let's call it c) is created and the original values of a and b are not needed anymore. The tuple is then assigned elementwise to the tuple on the left-hand side. The new value of a becomes c[0] (that is, former b) and the new value of b becomes c[1] (that is, former a+b).
Your code is not working because you are changing the value of a before evaluating b. In the Fibonacci series, you want the previous value of a and b. You can use list as above or can introduce another variable to store values.
while True:
temp = a + b
if temp >100:
break
print(temp)
a = b
b = temp
For reference, here is a simple implementation using list:
lst = [0, 1]
while True:
temp = lst[-1]+lst[-2]
if temp>100:
break
lst.append(temp)
print(lst)

Is something special of while loop regarding the index?

Here is the code:
a = "218916754"
b = ""
while len(a) > 1:
b = b + a[0]
a = a[2:] + a[1]
b = b + a
print b
The result is "281749561". My question is, how this happens? In this code, there is no i, no i+=1 etc, how the iteration happens? Is something special about the while loop? I mean the index function is hidden in this while loop?
This line:
a = a[2:] + a[1]
results in a string that is one character shorter than the previous. Once this string has a length of 1, the loop exits.
There is no "index function" or index "i" in a while clause. Instead, code such as:
while <expression>:
<body>
means, "repeat <body> as long as <expression> is True"
Initially when we are programming we are always using indexes (commonly - i,x,y,t) to keep track of iterations of loops. It is because we always have a loop that we want to run for a know fixed number of iterations. But indexes are not something fundamental to the loop. Loops are tools which are much more than that.
A loop consists of a condition and body. The body is executed as many times, depending on whether the condition is True or False. (Conditions are boolean conditions).
So in the given code the condition is len(a)>1. That is - if the length of string "a" is greater than 1. So the body of the loop will be executed as many times as long as this condition is true. (You can also see, if wrongly implemented you could have loops that do not terminate).
To see what exactly is happening in this particular program, You can use the print statement inside the loop and a dummy variable "iteration_num" which I am using to keep track of the iterations. Go ahead and run the following code and see for yourself.
a = "218916754"
b = ""
iteration_num = 1
while len(a) > 1:
b = b + a[0]
a = a[2:] + a[1]
print "iteration number: " + str(iteration_num)
print "a: " + a
print "b: " + b
iteration_num = iteration_num + 1
b = b + a
print b

Understanding recursion with the help of Iteration

def unZip(master3):
c = len(master3)
sub1=''
sub2=''
for i in range(0,c,2):
sub1+=master3[i]
sub2+=master3[i+1]
print(sub1,",",sub2)
basically I have written this code that separates alternative char from string and shows them separately,
I have been trying to convert or comprehend this with recursion but I have been failing lately.
Here is my try, can someone tell me how should I approach it?
def unzip(a):
storage1=''
storage2=''
storage3=''
storage4=''
if len(a)==0:
return 0
else:
if len(a)>=1:
storage1=a[0::2]
storage2=a[1::2]
storage3+=storage1
storage4+=storage2
print(storage3,storage4)
return unzip(a[0]+a[1:])
instead of using slicing to determine your strings you should be taking one character at a time off your string and then recalling your recursive function like so
def unzip(s, a, b='', c=''):
if len(a) == 0:
return b + ', ' + c
if s%2 == 0:
b += a[0]
else:
c += a[0]
return unzip(s+1, a[1:], b, c)
print unzip(0, 'HelloWorld')
Hlool, elWrd
What that does is it starts with the string a and alternates between adding to b or c with the variable s depending on whether it is even or odd. Add the first letter of a to either b or c and then remove that letter from a. Then call the function again but with s+1. If the length of a is zero then return b and c and then print your result
To get the same results with what you have you could simplify yours down to
a = 'HelloWorld'
storage1=a[0::2]
storage2=a[1::2]
print(storage1,storage2)
('Hlool', 'elWrd')
The slicing takes care of getting every other letter in a and then you can just print that. The way you have it set up now it will just keep passing a and become an infinite loop since the size of a will never change.

Categories