I'm calling a function inside itself many times to solve the subset sum problem, using as it called, the recursion solution; anyway, I can't figure out why n (which is the number of elements of the array) value is getting decreasing at first, until it reach 0, which is I get it, but then, after calling it again within itself, it makes n value incremented. Why is that happening, as the whole function doesn't even have an increment contribution for the n value? Where n gets its increasing value from?
Here is the code:
def printAllSubsetsRec(arr, n, currentSubset, sum):
# If remaining sum is 0, then print all
# elements of current subset.
if (sum == 0):
i = 0
sumOfValue = 0
for value in currentSubset:
i += 1
sumOfValue += value
if (i == len(currentSubset)):
print(value, " = ", sumOfValue)
else:
print(value, end=" + ")
return True
# If there are no elements in the array and the sum is not equal to 0.
if (n == 0 and sum != 0):
return None
# I consider two cases for every element:
# a) Excluding last element.
# b) Including last element in current subset.
# -------------------------------------------------
# Excluding the last element:
printAllSubsetsRec(arr, n - 1, currentSubset, sum)
v = [] + currentSubset
v.append(arr[n - 1])
# Including the last element:
printAllSubsetsRec(arr, n - 1, v, sum - arr[n - 1])
#Main:
arr = [10, 7, 5, 18, 12, 20, 15]
sum = 35
n = len(arr)
currentSubset = []
printAllSubsetsRec(arr, n, currentSubset, sum)
The output should be:
18 + 7 + 10 = 35
12 + 18 + 5 = 35
20 + 5 + 10 = 35
15 + 20 = 35
Thanks in advance!
Recursion is a functional heritage and so using it with functional style yields the best results. This means avoiding things like mutation, variable reassignment, and other side effects -
logical if without a corresponding else
mutation and reassignment of i and sumOfValue
side effects like print
Recursion doesn't have to be difficult or painful. Using functional disciplines we can write subsets(t,n) with inductive reasoning -
If the target sum n is zero, yield the empty solution
(inductive) otherwise n is negative or positive. If n is negative or the input array t is empty, we are out-of-bounds. stop iteration.
(inductive) n is positive and t has at least one element. For all s of the subproblem (t[1:],n-t[0]), prepend t[0] to s and yield. And yield all results of the subproblem (t[1:],n)
def subsets(t, n):
if n == 0:
yield () #1
elif n < 0 or not t:
return #2
else:
for s in subsets(t[1:], n - t[0]): #3
yield (t[0], *s)
yield from subsets(t[1:], n)
for s in subsets([10, 7, 5, 18, 12, 20, 15], 35):
print(s)
(10, 7, 18)
(10, 5, 20)
(5, 18, 12)
(20, 15)
Notice -
All operations do not mutate or reassign variables
Side effects like print are traded for yield
Caller is free to utilize and transform the results any way desired
To format the results as an mathematical expression -
for s in subsets([10, 7, 5, 18, 12, 20, 15], 35):
print(" + ".join(map(str, s)), "=", 35)
10 + 7 + 18 = 35
10 + 5 + 20 = 35
5 + 18 + 12 = 35
20 + 15 = 35
To collect all outputs of a generator into a list, use list -
print(list(subsets([10, 7, 5, 18, 12, 20, 15], 35)))
[(10, 7, 18), (10, 5, 20), (5, 18, 12), (20, 15)]
Related
I wonder if there is any function in python like that.
Example 01:
For example, if I specify the range from (1,12) integer. Then:
if current value is 12 and I add 1, it return 1 (go back to minimum)
if current value is 11 and I add 3, it return 2
Example 02:
Another example is if I set range from (5, 9). Then:
If current value is 8 and I add 2, it return 5
If current value is 8 and I add 7, it return 5
I know I can write a self-defined function for that, I am just curious to know if python has that similar function built in
The self-defined function:
def wrap_range(val, nmin, nmax, add_val):
nrange = nmax - nmin + 1
remain = add_val % nrange
val = val + remain
if val <= nmax:
return val
else:
val = val - nmax + nmin - 1
return val
Itertools has the cycle and islice functions that you can use to get what you want -
from itertools import cycle, islice
def repeated_offset(nmin, nmax, start, n):
rng = range(nmin, nmax + 1)
start_idx = list(rng).index(start)
value, *_ = islice(cycle(rng), start_idx + n, start_idx + n + 1)
return value
repeated_offset(1, 12, 12, 1)
# 1
repeated_offset(1, 12, 11, 3)
# 2
repeated_offset(5, 9, 8, 2)
# 5
repeated_offset(5, 9, 8, 7)
# 5
What about looping, subtracting while the total value is bigger than the lower boundary, while subtracting range wide.
def loopit(val, the_min, the_max, addition):
total = val + addition
diff = the_max - the_min + 1
if not total > the_min:
raise ValueError("The total value must be larger then lowest boundary of the range")
while the_max < total:
total -= diff
return total
if __name__ == '__main__':
print(loopit(12, 1, 12, 1))
print(loopit(11, 1, 12, 3))
print(loopit(8, 5, 9, 2))
print(loopit(8, 5, 9, 7))
output:
1
2
5
5
i have this excesice:
*Given a list L, we indicate with 𝑥 the generic element of L and with 𝑥 the element in a symmetrical position to 𝑥. Write it down a function examine_list which receives a list L of positive integers of even length and returns a boolean. In in particular, the function returns True if and only if, for each element 𝑥 of L, the sum of the values of 𝑥 and 𝑥 is greater
the sum of the values of the elements positioned between 𝑥 and 𝑥.
Note that, when 𝑥 and 𝑥 are adjacent, the sum of the values of the elements positioned between 𝑥 and 𝑥 can be assumed equal to zero.
Example: If L = [12, 9, 7, 2, 1, 1, 3, 12] then the function returns True, because:
12 + 12> 9 + 7 + 2 + 1 + 1 + 3;
9 + 3> 7 + 2 + 1 + 1;
7 + 1> 2 + 1;
2 + 1> 0.*
My code is this:
def sum_list(l):
list_sum = []
pst_num = 0
ult_num = -1
for num in range(len(l)//2):
list_sum.append(l[pst_num]+l[ult_num])
pst_num +=1
ult_num -=1
return list_sum
def examine_list(l):
somme_xd = sum_list(l)
list_without_first_nums = []
first = 1
last = -1
for n in range(len(l)//2):
list_without_first_nums.append(l[first:last])
first += 1
last -= 1
st_sum = 0
count = 0
for lists in range(len(list_without_first_nums)):
for nums in range(len(list_without_first_nums[lists])):
if somme_xd[st_sum] >= sum(list_without_first_nums[lists][nums]):
st_sum += 1
count += 1
if count == len(somme_xd):
return True
else:
return False
L = [12, 9, 7, 2, 1, 1, 3, 12]
examine_list(L)
I have created the sum_list who create a list of sums of the array.
my problem is the 2nd function: sum gives me always thid error:
Traceback (most recent call last):
File "C:\Users\ALESSA~1\AppData\Local\Temp\tempCodeRunnerFile.python", line 35, in <module>
examine_list(L)
File "C:\Users\ALESSA~1\AppData\Local\Temp\tempCodeRunnerFile.python", line 26, in examine_list
if somme_xd[st_sum] >= sum(list_without_first_nums[lists][nums]):
TypeError: 'int' object is not iterable
You could use recursion for this:
def examine_list(L):
return not L or L[0]+L[-1]>sum(L[1:-1]) and examine_list(L[1:-1])
L = [12, 9, 7, 2, 1, 1, 3, 12]
print(examine_list(L)) # True
Or a comprehension with the all() function:
def examine_list(L):
return all(L[i]+L[-1-i]>sum(L[i+1:-1-i]) for i in range(len(L)//2))
To avoid repeatedly adding subranges of the list (which is somewhat inefficient), you can do it in a loop that starts out with the total and progressively decreases it with the leftmost/rightmost items as it progresses inwards:
def examine_list(L):
total = sum(L)
for a,b in zip(L,reversed(L)): # progress inwards from both sides
total -= a+b # reduce total to get sum in between
if a+b <= total: return False # not x+x' > in-between sum
if total == 0: break # reached middle, stop
return True
I need to use the formula v = (start * 2) + 5 to print the resulting values. The start parameter is the value in which the sequence starts and the count parameter is how many values get printed. I have no idea how to get the base case to get called.
def print_sequence_rec(start, count):
else:
v = (start * 2) + 5
print(v, end="")
print_sequence_rec(start, count + 1)
For example, the function print_sequence_rec(2, 5) should print 2 9 23 51 107 219
Make that count - 1 instead of + 1 so that count decreases by one each call. The base case is when count == 0.
You'll also need to do something with v. I suggest passing it to the recursive invocation.
def print_sequence_rec(start, count):
# base case
if count == 0:
pass
# recursive case
else:
v = (start * 2) + 5
print(v, end="")
print_sequence_rec(v, count - 1)
Or more likely you should get rid of it and move the computation to the recursive call:
def print_sequence_rec(start, count):
# base case
if count == 0:
pass
# recursive case
else:
print(start, end="")
print_sequence_rec((start * 2) + 5, count - 1)
John's answer does a nice job addressing your question, but this actually seems like a good case to use a generator.
For example...
def gen_sequence_rec(start, count):
while count >= 0:
yield start
start = (start * 2) + 5
count -= 1
...then you can save the sequence as a list...
seq = list(gen_sequence_rec(2,5))
#[2, 9, 23, 51, 107, 219]
...and print however you want...
print(seq)
[2, 9, 23, 51, 107, 219]
print(' '.join([str(x) for x in seq]))
2 9 23 51 107 219
Given the list:
n = [3, 6, 12, 24, 36, 48, 60]
I need to turn a random number divisible by 3, after by 6, after by 12, after by 24, after by 36, after by 48 and after by 60. One at each time, not the divisible for the seven numbers simultaneously.
But, to make the number divisible, I need to sum another number to reach the number divisible by 3, 6, 12, 24, 36, 48 or 60.
I don't know the random number neither the number to add to this random number in order to turn it divisible by 3, 6, 12, 24, 36, 48 or 60.
Can someone help me, please?
Using the map function list comprehension:
import random
n = [3, 6, 12, 24, 36, 48, 60]
a = random.randint(start, stop)
result = [a + x - a % x if a % x else a for x in n]
addition = [x - a for x in result]
print(a)
print(result)
print(addition)
start and stop are the limits for your random number.
Output for a = 311:
311
[312, 312, 312, 312, 324, 336, 360]
[1, 1, 1, 1, 13, 25, 49]
Begin of the old answer to the rather unclear question before the first edit by the author.
The following post answers the question: Which is the next number after a, which is a multiple of all numbers of the list n, if it is not a?
First the least common multiple lcm of the numbers from the list must be determined. For this purpose, the method least_common_multiple is executed for the complete list. The modulo operation then checks whether a is not already a multiple of the numbers. If this is the case, a is output. Otherwise, the next multiple of lcm is output.
from math import gcd
from functools import reduce
n = [3, 6, 12, 24, 36, 48, 60]
a = 311
def least_common_multiple(x, y):
return abs(x * y) // gcd(x, y)
lcm = reduce(least_common_multiple, n)
result = a if a > 0 else 1 # can be change if necessary, see edit
mod = result % lcm
if mod:
result += (lcm - mod)
print('Current number: ' + str(a))
print('The next number divisible by any number from the given list: ' + str(result))
print('Necessary addition: ' + str(result - a))
Output:
Current number: 311
The next number divisible by any number from the given list: 720
Necessary addition: 409
Edit: Changed the code so that 0 is no longer a valid result for a non-positive a.
However, if it is valid, you can change the code at the commented part with: result = a.
New answer for the clarified question:
import math
def f(x, a):
return math.ceil(a / x) * x - a
n = [3, 6, 12, 24, 36, 48, 60]
a = 311
result = [f(x, a) for x in n]
print(result)
Old answer:
I think you're looking for the LCM (lowest common multiple) of all numbers in n. We can get the LCM for two numbers using the GCD (greatest common divisor). We can then use reduce to get the LCM for the whole list. Assuming x can be negative, simply subtract a from the LCM to get your answer. The code could look like this:
import math
from functools import reduce
def lcm(a, b): # lowest common multiple
return a * b // math.gcd(a, b)
n = [3, 6, 12, 24, 36, 48, 60]
smallest_divisible_by_all = reduce(lcm, n)
a = 311
x = smallest_divisible_by_all - a
print(x)
which outputs
409
If speed is not important, you could also do a brute force solution like this:
ns = [3, 6, 12, 24, 36, 48, 60]
a = 311
x = 0
while not all([(a + x) % n == 0 for n in ns]):
x += 1
(assuming that x >= 0)
So I can think of 2 solutions:
First if you want a list which show how much you have to add for the random number to get to a divisible number:
def divisible(numbers,random):
l = []
for number in numbers:
if random % number != 0:
l += [number - (random % number)]
else:
l += [0]
return l
a = 311
n = [3, 6, 12, 24, 36, 48, 60]
print(divisible(n,a))
Output:
[1, 1, 1, 1, 13, 25, 49]
Or if you want to know how far is the smallest number from the random number that everyone shares as divisible. For this take a look how you calculate lcm.
from math import gcd
def divisible_all(numbers, random):
lcm = numbers[0]
for i in numbers[1:]:
lcm = lcm*i//gcd(lcm, i)
tempLcm = lcm
while lcm < random: # in case the lcm is smaller than the random number add lcm until it is bigger (I assume you only allow positive numbers)
lcm += tempLcm
return lcm-random
print(divisible_all(n,a))
Output:
409
You can do:
import math
n = [3, 6, 12, 24, 36, 48, 60]
div_n={el: False for el in n}
a=311
a0=math.ceil(a/max(n)) * max(n)
while not all(div_n.values()):
div_n={el: False for el in n}
# print(a0)
for el in n:
if(a0 % el > 0):
a0=math.ceil(a0/el) * el
break
else:
div_n[el]=True
print(a0-a)
Output:
409
I'm trying to find the avg of list but only when n >= 10 (two digit numbers, my original list is limited to 100).
Here's what I have right now:
# Calculate average of all two-digit numbers (10-99)
grade_list = [10, 11, 12, 13, 14, 15]
def calcAvg(grade_list):
while n > 10:
total = sum(grade_list)
n = total % len(grade_list)
print_list = n
return print_list
I get that I have to find the total sum of the list when n > 10 and then dividing by the length (only > 10, my original list has single digit elements, so I'd like to avoid them).
But when I run it, I get an error saying: local variable 'n' referenced before assignment
Any help on how to structure this function to achieve the end results (sum/total of only 2-digit elements = avg)
Thanks!
I'd either collect the good grades and use sum/len, or use the mean function:
>>> grade_list = [1, 2, 10, 11, 12, 13, 14, 15]
>>> good = [g for g in grade_list if g > 10]
>>> sum(good) / len(good)
13.0
>>> import statistics
>>> statistics.mean(g for g in grade_list if g > 10)
13.0
def calcAvg(grade_list):
my_list = []
total, count = 0,0
for n in grade_list:
if 10 <= n <= 99:
total += n
if not total:
return None
return total/count
Here is a clean way of doing it:
def calc_avg(lst):
filtered_lst = filter(lambda x: 10 < x < 100, lst)
return sum(filtered_lst) / len(filtered_lst)
So you should use a for loop instead of a while loop. Instead of having two for loops and making a new list, you could just account for the sum inside the first for loop. I demonstrate this below.
def calcAvg(grade_list):
sum = 0;
count = 0;
for n in grade_list:
if 10 <= n <= 99:
sum = sum + n
count = count + 1
return sum/count
I think you should manually go over the code step by step and try to understand what is wrong. Meanwhile this may give you some hints
# Calculate average of all two-digit numbers (10-99)
def calcAvg(alist):
count=total=0
for i in alist:
if 9 < i < 100:
total += i
count += 1
return total/count
Since Python 3.4 there is a statistics module.
So you just need to filter out numbers in range <10,100), for example with a list comprehension, and then pass this filtered list to the mean function. Simple as that.
from statistics import mean
numbers = [1, 20, 30, 50]
mean([n for n in numbers if n >= 10 and n < 100])
>>> 33.333333333333336
You could do this fairly simply with a list comprehension
>>> grades = [1, 2, 10, 11, 12, 13, 14, 15, 120, 122, 320]
>>> lst = [v for v in grades if 10 <= v < 100]
>>> sum(lst)/len(lst)
12