How to append a while function to list? - python

How does one append the output of a while function into a list? For example:
fib = []
def FIB():
a,b = 0,1
while a < 100:
fib.append(a)
a, b = b, a + b
print(fib)
I am expecting:
[0,1,1,2,3,5,8,13,21,34,55,89]
But I receive:
[]

you need to return fib, so you can print it. You also need to call your function correctly.
fib = []
def FIB():
a,b = 0,1
while a < 100:
fib.append(a)
a, b = b, a + b
return fib
print(FIB())

fib = []
def FIB(fib):
a,b = 0,1
while a < 100:
fib.append(a)
a, b = b, a + b
return fib
print(FIB(fib))

Related

3Sum function debugging

I have been asked to fix this chunk of code. It is to do with sets and the 3Sum problem. I have used print statements and i am very close to the answer, but i get an IndexingError (list index out of range). Any help would be great
def count_c(A, B, C):
"""Counts the number of pairs a in A and b in B so that a + b == c
nb. Assumes that A and B are sorted
"""
rv = 0
n = len(A)
m = len(B)
#t = len(C)
AL, BL, CL = list(A), list(B), list(C)
# i and j are "fingers" on A and B
i, j = 0, m-1
while i < n and j >= 0:
for c in CL:
a, b = AL[i], BL[j] #correct
print ('a,b = ', (a,b))
s = a + b #correct
print('s = ', s)
print ('i , j =', (i,j))
if s == c:
# found a pair that works
rv = rv + 1 #correct
# start again with a smaller b
j = j - 1 #correct
elif s > c:
# too big. decrease the b contribution
j = j - 1
else:
# means s < c, increase the a contribution
i = i + 1
return rv
def three_sum(A, B, C):
"""Solves 3SUM+"""
return count_c(A,B,C)
IndexingError (list index out of range)

Solving a function that measures distance between points in a list of points (x, y)

I am writing a function route. This function has a mandatory parameter points that takes a list of points. The function must return the total distance traveled if each of the points in the given list is visited in turn. Apart from the mandatory parameter, the function also has two optional parameters:
cycle: takes a Boolean value that indicates whether the end of the route is equal to its starting point (True) or not (False); the default value of this parameter is False
distance: takes a distance function that is used for the calculation of the total distance between two consecutive points in the given route; if no explicit value is passed to this parameter, the Euclidean distance must be used
Problem: Anybody knows with the last definition route() how to solve it for the case:
route([(41.79, 13.59), (41.68, 14.65), (21.16, -4.79)], distance=lambda p1, p2: abs(p1[0] + p2[0]))
correct answer : 146.31
Part of my code I refer to:
if cycle == False and distance is λ(p1, p2): abs(p1[0] + p2[0]):
l = list()
count = 0
for items in range(len(points)-1):
a = points[items]
b = points[items+1]
d = euclidean(a[0], b[0])
l.append(d)
count += 1
return sum(l)
In this part I got stuck at the first rule and further.
Complete code which works fine (except for the part above):
def euclidean(a, b):
'''
>>> euclidean((42.36, 56.78), (125.65, 236.47))
198.05484139500354
'''
from math import sqrt
return sqrt(sum((a - b)**2 for a, b in zip(a, b)))
def manhattan(c, d):
'''
>>> manhattan((42.36, 56.78), (125.65, 236.47))
262.98
'''
return sum(abs(c - d) for c, d in zip(c, d))
def chessboard(e, f):
'''
>>> chessboard((42.36, 56.78), (125.65, 236.47))
179.69
'''
return max(abs(e - f) for e, f in zip(e, f))
def route(points, cycle=False, distance=None):
'''
>>> route([(6.59, 6.73), (4.59, 5.54), (5.33, -13.98)])
21.861273201261746
>>> route(cycle=True, points=[(6.59, 6.73), (4.59, 5.54), (5.33, -13.98)])
42.60956710702662
>>> route([(6.59, 6.73), (4.59, 5.54), (5.33, -13.98)], distance=manhattan)
23.45
>>> route([(6.59, 6.73), (4.59, 5.54), (5.33, -13.98)], cycle=True, distance=manhattan)
45.42
'''
if cycle == False and distance is None:
l = list()
count = 0
for items in range(len(points)-1):
a = points[items]
b = points[items+1]
d = euclidean(a, b)
l.append(d)
count += 1
return sum(l)
if cycle == False and distance is euclidean:
l = list()
count = 0
for items in range(len(points)-1):
a = points[items]
b = points[items+1]
d = euclidean(a, b)
l.append(d)
count += 1
return sum(l)
if cycle == False and distance is λ(p1, p2): abs(p1[0] + p2[0]):
l = list()
count = 0
for items in range(len(points)-1):
a = points[items]
b = points[items+1]
d = euclidean(a[0], b[0])
l.append(d)
count += 1
return sum(l)
if cycle == True and distance is None:
l = list()
count = 0
for items in range(len(points)-1):
a = points[items]
b = points[items+1]
d = euclidean(a, b)
l.append(d)
count += 1
f = points[0]
g = points[-1]
r = euclidean(g, f)
k = sum(l) + r
return k
if cycle == True and distance is euclidean:
l = list()
count = 0
for items in range(len(points)-1):
a = points[items]
b = points[items+1]
d = euclidean(a, b)
l.append(d)
count += 1
f = points[0]
g = points[-1]
r = euclidean(g, f)
k = sum(l) + r
return k
if cycle is False and distance is manhattan:
l = list()
count = 0
for items in range(len(points)-1):
a = points[items]
b = points[items+1]
d = manhattan(a, b)
l.append(d)
count += 1
return sum(l)
if cycle is True and distance is manhattan:
l = list()
count = 0
for items in range(len(points)-1):
a = points[items]
b = points[items+1]
d = manhattan(a, b)
l.append(d)
count += 1
f = points[0]
g = points[-1]
r = manhattan(g, f)
k = sum(l) + r
return k
I Agree with Duncan. You have way too much duplication.
Here a more direct approach:
euclidean = lambda p1, p2: sqrt(sum((p1_i - p2_i)**2 for p1_i, p2_i in zip(p1, p2)))
manhattan = lambda p1, p2: sum(abs(p1_i - p2_i) for p1_i, p2_i in zip(p1, p2))
chessboard = lambda p1, p2: max(abs(p1_i - p2_i) for p1_i, p2_i in zip(p1, p2))
def route(points, cycle=False, metric=euclidean):
l = 0.0
for i in range(len(points) - 1):
l += metric(points[i], points[i + 1])
if cycle:
l += metric(points[-1], points[0])
return l
Any metric funtion can be passed and is then used instead of the euclidean metric.

Generate 2D array in different ways

This is a DP problem, which I solve using 2D array in python.
The problem is the way I generate the 2D array.
Standard solution:
def getFloor(F, c, d):
if d == 0 or c == 0:
return 0
if c == 1:
return d
if F[c][d] == -1:
F[c][d] = getFloor(F, c, d-1) + getFloor(F, c-1, d-1) + 1
return F[c][d]
def getMaxFloor(c,d):
F = [[-1] * (d + 1) for i in range(c + 1)]
ans = getFloor(F, c, d)
return ans
print(getMaxFloor(3,4)) #prints 14
My code:
def getFloor(F, c, d):
if d == 0 or c == 0:
return 0
if c == 1:
return d
if F[c][d] == -1:
F[c][d] = getFloor(F, c, d-1) + getFloor(F, c-1, d-1) + 1
return F[c][d]
def getMaxFloor(c,d):
F = [[-1] * (d + 1)] * (c+1)
ans = getFloor(F, c, d)
return ans
print(getMaxFloor(3,4)) #prints 15, instead of the correct answer 14
I check both of the arrays F when both are initialized, which returns true.
What's the problem?
I'm guessing the problem is that when you multiply it, you are just creating duplicates or references to the same list element. So if you change one, you change the other. Whereas if you use the for loop, it creates separate unlinked instances so that when one gets changed it does not affect the other. (You would have to do a lot of tracing back, etc. to figure out exactly why the answer is off by exactly 1.) But this is really the only difference between the codes so it must be the problem. Hope this helps.
For example:
l = [1,2,3]
a = [2]
l.append(a)
a[0] = 4
print l
>>>[1, 2, 3, [4]]
Notice that the last element in l is [4] instead of [2].

Replace simple while loop by recursion

If I have an simple function (pseudocode) like
fun(a, b):
x = a
i = 0
while i < b do
x = x + a
i ++
return x
Can I replace the while loop in this function by a recursion?
Something like:
fun (a, b, i):
if i >= b:
return 1
else:
return a + fun(a, b, i + 1)
Without using an extra parameter you can try:
def f(a, b):
if b <= 1:
return a
else:
return a + f(a, b - 1)
Note: This will only work for b >= 1.
def fun(x, y):
if y != 0:
for i in fun(x, y-1):
yield x + i
yield 0

Python: string formatting and calling functions

So I'm running in to the string formatting error when trying to pass the arguments num1 and num2 to the function gcd. I'm not sure how to fix this. Please bear with me since I'm new to Python programming. Thanks!
#!/usr/bin/python
import sys
from collections import defaultdict
lines = sys.stdin.read()
lineArray = lines.split()
listLength = len(lineArray)
def gcd(a, b):
c = 0
if a > b:
r = a%b
if r == 0:
return b
else:
return gcd(b, r)
if a < b:
c = b
b = a
a = c
return gcd(a, b)
for x in range(0, listLength):
num1 = lineArray[x]
num2 = lineArray[x+1]
print num1, 'and', num2
print gcd(num1, num2)
print 'end'
It's pretty simple. lineArray is not a list containing integers, but strings.
So when you do this:
r = a%b
It tries to format the string a, instead of calculating a%b.
To solve this, convert a and b to integers:
def gcd(a, b):
a,b = int(a),int(b)
c = 0
if a > b:
r = a%b
if r == 0:
return b
else:
return gcd(b, r)
if a < b:
c = b
b = a
a = c
return gcd(a, b)
Also, in your gcd function, the recursion never ends. Hint: You'll have to check if b is 0.
Hope this helps!

Categories

Resources