sum variable in a range (python) - python

This was the question:
Write a function called sum_range that accepts 2 integer values as
parameters and returns the sum of all the integers between the two
values, including the first and last values. The parameters may be in
any order (i.e. the second parameter may be smaller than the first).
For example:
result = sum_range(1, 1)
print(result) 1
result = sum_range(2, 4) print(result) 9
result = sum_range(3, 2)
print(result) 5
my codes are as below, I dont know where it went wrong
but when I test the codes, it returned 'none' when (2,4) (3,2) were entered
def sum_range(x,y):
if x == y:
return x
if x<y:
sum(range(x,y))
return
if x>y:
sum(range(y,x))
return

You could do better (at least I think), here is my code for that:
def sum_range(a, b):
return sum(range(min(a,b),max(a,b)+1))

You were very close but forgot to return the actual value from the calculations. If you just type "return", you will return None and not the result from the sum.
You also did not include the last number in the range in the sum. See corrected code below:
def sum_range(x, y):
if x == y:
return x
if x < y:
return sum(range(x, y+1))
if x > y:
return sum(range(y, x+1))

You need to return the sum which you are not doing in the x<y and x>y cases. You should
return sum(range(x,y)) or return sum(range(y,x)) as appropriate.
Note also that there is a bug in your range() expressions - "including the first and last values". Hint: What does range(1,3) output?

def sum_range(x,y):
if x == y:
return x
elif x < y:
s = 0
for i in range(x,y):
s += x+(x+1)
return s
elif x > y:
s = 0
for i in range(y,x):
s += y+(y+1)
return s
This is done without using sum() function.

Related

recursively calculate if x is power of b

The assignment is to write a recursive function that receives 2 whole non-negative numbers b, x, and returns True if there's a natural integer n so that b**n=x and False if not. I'm not allowed to use any math operators or loops, except % to determine if a number is even or odd.
but i do have external functions that i can use. Which can add 2 numbers, multiply 2 numbers, and divides a number by 2. also i can write helper function that i can use in the main function.
this is what i got so far, but it only works if b is in the form of 2^y (2,4,8,16 etc)
def is_power(b, x):
if b == x:
return True
if b > x:
return False
return is_power(add(b, b), x) # the func 'add' just adds 2 numbers
Furthermore, the complexity needs to be O(logb * logx)
Thank you.
You can essentially keep multiplying b by b until you reach, or pass, n.
A recursive implementation of this, using a helper function, could look something like this:
def is_power(b, x):
if b == 1: # Check special case
return x == 1
return helper(1, b, x)
def helper(counter, b, x):
if counter == x:
return True
elif counter > x:
return False
else:
return helper(mul(counter, b), b, x) # mul is our special multiplication function
Use the function you say you can use to multiply 2 numbers like:
power = False
result = b
while result < x:
result = yourMultiplyFunction(b,b)
if result == x:
power = True
break
print(power)
Question was EDITTED (can't use loops):
def powerOf(x, b, b1=-1):
if b1 == -1:
b1 = b
if (b == 1) and (x == 1):
return True
elif ( b==1 ) or (x == 1):
return False
if b*b1 < x:
return powerOf(x, b*b1, b1)
elif b*b1 > x:
return False
return True
print(powerOf(625, 25))
A solution that is O(logb * logx) would be slower than a naive sequential search
You can get O(logx / logb) by simply doing this:
def is_power(b,x,bn=1):
if bn == x: return True
if bn > x: return False
return is_power(b,x,bn*b)
I suspect that the objective is to go faster than O(logx/logb) and that the complexity requirement should be something like O(log(logx/logb)^2) which is equivalent to O(log(n)*log(n)).
To get a O(log(n)*log(n)) solution, you can convert the problem into a binary search by implementing a helper function to raise a number to a given power in O(log(n)) time and use it in the O(log(n)) search logic.
def raise_power(b,n): # recursive b^n O(logN)
if not n: return 1 # b^0 = 1
if n%2: return b*raise_power(b*b,n//2) # binary decomposition
return raise_power(b*b,n//2) # of power over base
def find_power(b,x,minp,maxp): # binary search
if minp>maxp: return False # no matching power
n = (minp+maxp)//2 # middle of exponent range
bp = raise_power(b,n) # compute power
if bp == x: return True # match found
if bp > x: return find_power(b,x,minp,n-1) # look in lower sub-range
return find_power(b,x,n+1,maxp) # look in upper sub-range
def max_power(b,x):
return 2*max_power(b*b,x) if b<x else 1 # double n until b^n > x
def is_power(b,x):
maxp = max_power(b,x) # determine upper bound
return find_power(b,x,0,maxp) # use binary search
Note that you will need to convert the *, + and //2 operations to their equivalent external functions in order to meet the requirements of your assignment

Return second smallest number in a nested list using recursion

I have to return the second smallest number in a python list using recursion, and no loops. What I have done is created a helper function that returns a tuple of the (smallest, second smallest) values in the list, and then I just take the tuple[1] in my second_smallest func.
def s_smallest(L):
if(len(L) == 2):
if (L[0] >= L[1]):
return (L[1],L[0])
else:
return (L[0],L[1])
else:
first_smallest,second_smallest = s_smallest(L[1:])
if L[0] >= first_smallest and L[0] <= second_smallest:
return (first_smallest, L[0])
elif L[0] <= first_smallest:
return (L[0], first_smallest)
else:
return (first_smallest, second_smallest)
This works, but now I need to handle nested lists, so s_smallest([1,2,[3,0]]) should return (0,1). I tried doing this:
if isinstance(L[0],list):
first_smallest,second_smallest = s_smallest(L[0])
else:
first_smallest,second_smallest = s_smallest(L[1:])
to get the first smallest and second smallest values if it is a list, but I get an error saying builtins.TypeError: unorderable types: int() >= list(). How can I fix this problem to deal with nested lists?
I might suggest separating the list unnesting and the min reducing into two separate, well-defined tasks
deepReduce will reduce a list of lists using the specified reducing function
deepMin performs a deepReduce using min
import math # used for math.inf
def min (x,y):
return x if x < y else y
def deepReduce (f, y, xs):
if not xs:
return y
elif isinstance(xs[0], list):
return deepReduce(f, deepReduce(f, y, xs[0]), xs[1:])
else:
return deepReduce(f, f(y, xs[0]), xs[1:])
def deepMin (xs):
return deepReduce (min, math.inf, xs)
data = [1,2,[7,[6,1,3,[0,4,3]],3,4],2,1]
print(deepMin(data))
# 0
Oh, but you said you want the second smallest number. Let's rework that code a little bit. Of course I knew that all along, but answering this question twice allows me to demonstrate the versatility of this specific implementation – Changes in bold
def min2 (xs, y):
# x1 is the smallest, x2 is second smallest
x1, x2 = xs
if (y < x1) and (y < x2):
return (y, x2)
elif y < x2:
return (x1, y)
else:
return (x1, x2)
def deepMin2 (xs):
# notice we change to use tuple of math.inf now
x1, x2 = deepReduce (min2, (math.inf, math.inf), xs)
return x2
data = [1,2,[7,[6,1,3,[0,4,3]],3,4],2,1]
print(deepMin2(data))
# 1
I should point out that we didn't have to touch deepReduce at all, which is the point – we should be able to do any arbitrary deep operation on our nested list without having to statically code that behaviour into our function.
Now you can write whatever deep reducer you want and call it with deepReduce
Full solution
Using nothing but functools.reduce, no loops, to handle lists of arbitrary nesting:
import functools
def helper(acc, x):
if type(x) is list:
return functools.reduce(lambda acc, x: helper(acc, x), x, acc)
else:
if x < acc[0]:
return (x, acc[0])
elif x < acc[1]:
return (acc[0], x)
else:
return (acc[0], acc[1])
def second_smallest(l):
if len(l) < 2:
return None
else:
if l[0] <= l[1]:
return functools.reduce(lambda acc, x: helper(acc, x), l[2:], (l[0], l[1]))
else:
return functools.reduce(lambda acc, x: helper(acc, x), l[2:], (l[1], l[0]))
>>> second_smallest([1,2,[0,3,[-1,-2]]])
(-2, -1)

How to stop a loop?

def sum_div(x, y):
for k in range(x,y+1):
for z in range(x,y+1):
sx = 0
sy = 0
for i in range(1, k+1):
if k % i == 0:
sx += i
for j in range(1, z+1):
if z % j == 0:
sy += j
if sx == sy and k!= z:
print "(", k ,",", z, ")"
x = input("Dati x : ")
y = input("Dati y : ")
sum_div(x, y)
How do I stop the looping if the value of z == y?
The loops print a pair of numbers in a range from x to y, but when it hit the y value the loop prints a reverse pair of numbers that I don't need it to.
The break command will break out of the loop. So a line like this:
if (z == y):
break
should do what you want.
What you're think you are asking for is the break command, but what you're actually looking for is removal of duplication.
Your program lacks some clarity. For instance:
for i in range(1, k+1):
if k % i == 0:
sx += i
for j in range(1, z+1):
if z % j == 0:
sy += j
These two things are doing essentially the same thing, which can be written more cleanly with a list comprehension (in the REPL):
>>> def get_divisors(r: int) -> list:
... return [i if r % i == 0 else 0 for i in range(1, r+1)]
...
...
>>> get_divisors(4)
>>> [1, 2, 0, 4]
>>> sum(get_divisors(4))
>>> 7
Your line:
while y:
... will infinitely loop if you find a match. You should just remove it. while y means "while y is true", and any value there will evaluate as true.
This reduces your program to the following:
def get_divisors(r: int) -> list:
return [i if r % i == 0 else 0 for i in range(1, r+1)]
def sum_div(x, y):
for k in range(x,y+1):
sum_of_x_divisors = sum(get_divisors(k)) # Note this is moved here to avoid repeating work.
for z in range(x,y+1):
sum_of_y_divisors = sum(get_divisors(z))
if sum_of_x_divisors == sum_of_y_divisors and k!= z:
print("({},{})".format(k, z))
Testing this in the REPL it seems correct based on the logic of the code:
>>> sum_div(9,15)
(14,15)
(15,14)
>>> sum_div(21, 35)
(21,31)
(31,21)
(33,35)
(35,33)
But it's possible that for sum_div(9,15) you want only one of (14,15) and (15,14). However, this has nothing to do with breaking your loop, but the fact that what you're attempting to do has two valid values when k and z don't equal each other. This is demonstrated by the second test case, where (33,35) is a repeated value, but if you broke the for loop on (21,31) you would not get that second set of values.
One way we can account for this is by reordering when work is done:
def sum_div(x, y):
result_set = set() # Sets cannot have duplicate values
for k in range(x,y+1):
sum_of_x_divisors = sum(get_divisors(k))
for z in range(x,y+1):
sum_of_y_divisors = sum(get_divisors(z))
if sum_of_x_divisors == sum_of_y_divisors and k!= z:
result_set.add(tuple(sorted((k,z)))) # compile the result set by sorting it and casting to a tuple, so duplicates are implicitly removed.
for k, z in result_set: # Print result set after it's been compiled
print("({},{})".format(k, z))
And we see a correct result:
>>> sum_div(9,15)
(14,15)
>>> sum_div(21,35)
(21,31)
(33,35)
Or, the test case you provided in comments. Note the lack of duplicates:
>>> sum_div(10,25)
(16,25)
(14,15)
(15,23)
(10,17)
(14,23)
Some takeaways:
Break out functions that are doing the same thing so you can reason more easily about it.
Name your variables in a human-readable format so that we, the readers of your code (which includes you) understands what is going on.
Don't use loops unless you're actually looping over something. for, while, etc. only need to be used if you're planning on going over a list of things.
When asking questions, be sure to always include test input, expected output and what you're actually getting back.
The current best-practice for printing strings is to use the .format() function, to make it really clear what you're printing.

How to put numbers in ascending, return them in a tuple, and add another argument.(Python)

Function signature :
def rank3(x,y,z, ascending=True)
Given three integers, return them in order in a tuple of
length three. An optional fourth argument (ascending) states whether output should be sorted ascending (argument is True) or descending (argument is False).
Examples:
§ rank3(5, 3, 4) → (3,4,5)
§ rank3(5, 3, 4, False) → (5,4,3)
§ rank3(6, 8, 6) → (6,6,8)
This is my code so far:
x = num1 #your first input
y = num2 #your second input
z = num3 #your third input
a = [x, y, z] #your list of inputs
b = [] #your sorted list
def rank3(x,y,z, ascending=True):
while a: # your sort function
o = a[0]
for i in a:
if i < o:
o = i
b.append(o)
a.remove(o)
return b #return your final answer
Try with
import bisect
def rank3(x,y,z, ascending=True):
if x <= y:
ret = [x, y]
else:
ret = [y, x]
pz = bisect.bisect(ret, z)
ret.insert(pz, z)
if not ascending:
ret = ret[::-1] # or use ret.reverse()
return tuple(ret)
In case you do not even want to use bisect, do a little while loop until you find an element in ret which is greater than z (hint, use enumerate)
However, this is shorter and more pythonic
def rank3(x,y,z, ascending=True):
return tuple(sorted((x,y,z), reverse=not ascending))
First of all - try to find answer in built-in python functions.
And after all write your own.
For your example python have a good method sorted(). And you can reverse your list/tuple by reverse() method.

How to get a single output from a function with multiple outputs?

I have the following simple function:
def divide(x, y):
quotient = x/y
remainder = x % y
return quotient, remainder
x = divide(22, 7)
If I accesss the variable x I get:
x
Out[139]: (3, 1)
Is there a way to get only the quotient or the remainder?
You are essentially returning a tuple, which is an iterable we can index, so in the example above:
print x[0] would return the quotient and
print x[1] would return the remainder
You have two broad options, either:
Modify the function to return either or both as appropriate, for example:
def divide(x, y, output=(True, True)):
quot, rem = x // y, x % y
if all(output):
return quot, rem
elif output[0]:
return quot
return rem
quot = divide(x, y, (True, False))
Leave the function as it is, but explicitly ignore one or the other of the returned values:
quot, _ = divide(x, y) # assign one to _, which means ignore by convention
rem = divide(x, y)[1] # select one by index
I would strongly recommend one of the latter formulations; it's much simpler!
You can either unpack the return values when you call your method:
x, y = divide(22, 7)
Or you can just grab the first returned value:
x = divide(22, 7)[0]

Categories

Resources