Generating unique Pythagorean triplets using this algorithm - python

def pyg(n):
n=int(n)
for i in range(1,n):
a=(2*i)+1
b=(2*i)*(i+1)
c=(2*i)*(i+1)+1
return(a,b,c)
When i try to run this on Shell using pyg(100) I only get output (3, 4, 5).
What might be the problem all the triplets are not generating.

As many others pointed out, when the return statement executes, your function will finish, and will not continue looping. However, you have options for returning multiple values from a single function. For example aggregating your values in a list and return that, or to use the yield keyword instead of return. The yield keyword will make your function a generator function, which returns an iterable generator object with all your expected elements.
I advise you to split your code into separate functions, so you have the original formula as a function of i, and a generator function which will return the elements for 1 <= i < n. Note that you can collect the elements of a generator to a list by supplying it to the list constructor.
def pyg(i):
a = (2*i) + 1
b = (2*i) * (i+1)
c = (2*i) * (i+1) + 1
return (a,b,c)
def pygs(n):
for i in range(1, n):
yield pyg(i)
print(list(pygs(10))) # prints the first 9 Pythagorean triplet as a list of tuples

The return sentence. Change it for a yield. If you want to test it, you could:
>>> pygs = pyg(100)
>>> next(pygs)
(3, 4, 5)
>>> next(pygs)
.
.
.

Your function produces only one pair, because return interrupts function execution. You could use yield keyword, as suggested by #jgomo3, or map function:
def generate_triplet(n):
a=(2*n)+1
b=(2*n)*(n+1)
c=(2*n)*(n+1)+1
return(a,b,c)
def pyg(n):
return map(generate_triplet, range(1, int(n))

Related

Why is my for loop printing memory location [duplicate]

N = [1, 2, 3]
print(n for n in N)
Results:
<generator object <genexpr> at 0x000000000108E780>
Why didn't it print?:
1
2
3
However the code:
sum(n for n in N)
Will sum up all the number in N.
Could you please tell me why sum() worked but print() failed?
It's because you passed a generator to a function and that's what __repr__ method of this generator returns. If you want to print what it would generate, you can use:
print(*N, sep='\n') # * will unpack the generator
or
print('\n'.join(map(str, N)))
Note that once you retrieve the generator's output to print it, the generator is exhausted - trying to iterate over it again will produce no items.
If you don't want to cast it as a list, you can try:
print(*(n for n in N))
See: https://docs.python.org/3/tutorial/controlflow.html#tut-unpacking-arguments
You are literally printing a generator object representation
If you want on one line, try printing a list
print([n for n in N])
Which is just print(N)
If you want a line separated string, print that
print("\n".join(map(str, N)))
Or write a regular loop and don't micro optimize the lines of code
Generator …
def genfun():
yield ‘A’
yield ‘B’
yield ‘C’
g=genfun()
print(next(g))= it will print 0th index .
print(next(g))= it will print 1st index.
print(next(g))= it will print 2nd index.
print(next(g))= it will print 3rd index But here in this case it will give Error as 3rd element is not there
So , prevent from this error we will use for loop as below .
for i in g :
print(i)

How do I perform an operation iteratively on a python list/array whithout a for loop?

Is it possible to perform the following operation on the first two elements of the list, storing the result and then performing the next operation on the previous result and the next item in the list for all items in the list without a for loop? Here F(x) is an arbitrarily defined function.
This is the working code with a for loop:
list = [a,b,c,d,e,f,g,h]
result = F(a,b)
for i in range(2,len(list)):
result = F(result,list[i])
print(result)
Thank you very much in advance, the best answer gets a pancake.
Yes, this is a reduction:
from functools import reduce
result = reduce(F, list)
reduce applies a function to an accumulator (result), along with each element of a list. In the first iteration though, if you don't specify an initial accumulator, it will use the initial element as the accumulator.
There is a reduce function to do this: https://www.geeksforgeeks.org/reduce-in-python/
# importing functools for reduce()
import functools
# initializing list
lis = [ 1 , 3, 5, 6, 2, ]
# using reduce to compute sum of list
print ("The sum of the list elements is : ",end="")
print (functools.reduce(lambda a,b : a+b,lis))
For your example
import functools
list = [a,b,c,d,e,f,g,h]
def F(a,b):
return a + b #or whatever
result = functools.reduce(F, list)
print(result)
you can write the funcction yourself:
def split_and_compute(_list):
if len(_list) > 2:
return myother_fun(_list[0:2]) + split_and_compute(_list[2:])
else:
return myother_fun(_list)
def myother_fun(_list):
return _list[0] + _list[1]
Note the + in return myother_fun(_list[0:2]) + split_and_compute(_list[2:]) should be whatever acumulator you have, depending on what data you are dealing with, also this dealswith 2 elements in a very hacky way, can put some guards in there

Is it possible to call more than one next value of an infinite python generator at once?

Is there any way to get the next n values of a generator without looping or calling next() n times?
The thing that the generator in this case is infinite, and cannot be translated into a list.
Here is the generator function:
def f():
a, b = 0, 1
while True:
yield a
a, b = b, a + b
The following loops both give the desired result, but I would like to know if there is some other method of doing this.
gen = f()
n = 0
while n < 10:
print(next(gen))
n += 1
or..
for n, i in enumerate(f()):
if n < 10:
print(i)
else:
break
There are several ways to do this. One way is to use list comprehension, similar to what you already have above. For instance:
gen = f()
elements = [next(gen) for _ in range(10)]
Another way is to use something like the itertools module, for instance the takeWhile()- or islice()-function.
Also check out How to get the n next values of a generator in a list (python).

How to run down a list with recursion?

At first, I had to do it without recursion (just by looping which is pretty easy).
Now I have to do it with recursion, but I am not allowed to use any loop.
I guess I have to run down the list with recursion, but I don't quite understand what should be my base, or the reduction...
def long_strings_rec(strings, N):
'''
strings - a list of strings
N - an integer
Returns all strings in 'strings' of length bigger then 'N'
(This function is recursive and does not use loops)
'''
# Your code for question #2 (second function) starts here
# Your code for question #2 (second function) ends here
Any ideas? Can I have maybe an example of how to use recursion to take actions on lists indexes?
I used the helper function to do that, like #7stud suggested:
def helper (strings, K, results):
if len(strings) == 0:
return 0
elif len(strings[0]) > K:
results.append(strings[0])
strings.pop(0)
else:
strings.pop(0)
helper(strings, K, results)
return results
def long_strings_rec (strings, N):
'''
strings - a list of strings
N - an integer
Returns all strings in 'strings' of length bigger then 'N'
(This function is recursive and does not use loops)
'''
# Your code for question #2 (second function) starts here
return helper(strings, N, [])
# Your code for question #2 (second function) ends here
Worked like a charm. Hope it's not buggy.
Here's an example of how to use an accumulator:
def sum(nums):
return helper(nums, 0) #0 is the initial value for the accumulator
def helper(nums, total): #total is the accumulator
if len(nums) == 0:
return total
else:
num = nums.pop()
return helper(nums, total+num)
print sum([1, 2, 3])
--output:--
6
Basically, you redefine sum() so that it takes an additional accumulator parameter variable, then have sum() call the new function.
See if you can apply those principles to your problem.
As bjorn pointed out in the comments, you could do it like this too:
def mysum(nums, total=0):
if len(nums) == 0:
return total
else:
num = nums.pop()
return sum(nums, total+num)
print mysum([1, 2, 3])
--output:--
6

concatenation and recursion

#Calculates to the index position of a fib number.
def f3(n):
if n < 2:
return n
return f3(n-2) + f3(n-1)
The function only accepts one argument, yet two are being sent in the return, yet, it works! What's happening here?
If I return f3(n-3), the function breaks down. What effect does the concatenation have?
Addition results in a single value.
>>> 1 + 2
3
>>> [1] + [2]
[1, 2]
Python evaluates the expression f3(n-2) + f3(n-1) before returning it, so its actually returning the value of them combined. The same is the case for f3(n-2), its first evaluating n-2 and then passing it as a value to f3().
The number of return arguments has nothing to do with the number of arguments a function takes as input.
The line f3(n-2) + f3(n-1) is returning only one value, the result of calculating f3 for the input n-2 and then adding that value to the result of calculating f3 for the input n-1
In Python, the mechanism for returning multiple values from a function is by packing them inside a tuple and then extracting them at the time of invoking the function (not the case in your question!) For example:
def multivalue(x, y)
return (x, y)
a, b = multivalue(5,10)
# here a holds 5, and b holds 10

Categories

Resources