Finding all unique values that add up to specific target value - python

Is there a more Pythonic way to find all combinations of numbers (each combination is made up of unique numbers) that add up to a specific target number. For example:
largest_single_number = 9 # in this example: single digits only
num_of_inputs = 5
target_sum = 30
# expected output:
0 + 6 + 7 + 8 + 9 = 30
1 + 5 + 7 + 8 + 9 = 30
2 + 4 + 7 + 8 + 9 = 30
2 + 5 + 6 + 8 + 9 = 30
3 + 4 + 6 + 8 + 9 = 30
3 + 5 + 6 + 7 + 9 = 30
4 + 5 + 6 + 7 + 8 = 30
number of possibilities: 7
The code we have looks like this:
counter = 0
largest_single_number = 9 # in this example: single digits only
num_of_inputs = 5 # Not used but dictates number of nested loops
target_sum = 30
for digit_1 in range(largest_single_number + 1):
for digit_2 in range(digit_1 + 1, largest_single_number + 1):
for digit_3 in range(digit_2 + 1, largest_single_number + 1):
for digit_4 in range(digit_3 + 1, largest_single_number + 1):
for digit_5 in range(digit_4 + 1, largest_single_number + 1):
if (
digi_sum := (digit_1 + digit_2 + digit_3 + digit_4 + digit_5)
) == target_sum:
print(
f"{digit_1} + {digit_2} + {digit_3} + {digit_4} + {digit_5} = {target_sum}"
)
counter += 1
elif digi_sum > target_sum:
break
print("number of possibilities: ", counter)
We would appreciate knowing what's a more Pythonic way to achieve the SAME RESULT.

Use itertools.combinations
Check the equality in a List Comprehensions
from itertools import combinations
values = [x for x in combinations(range(10), 5) if sum(x) == 30]
print(len(values))
>>> 7
print(values)
[(0, 6, 7, 8, 9),
(1, 5, 7, 8, 9),
(2, 4, 7, 8, 9),
(2, 5, 6, 8, 9),
(3, 4, 6, 8, 9),
(3, 5, 6, 7, 9),
(4, 5, 6, 7, 8)]
To get your expected output
for x in values:
expected = ' + '.join(map(str, x)) + ' = 30'
print(expected)
0 + 6 + 7 + 8 + 9 = 30
1 + 5 + 7 + 8 + 9 = 30
2 + 4 + 7 + 8 + 9 = 30
2 + 5 + 6 + 8 + 9 = 30
3 + 4 + 6 + 8 + 9 = 30
3 + 5 + 6 + 7 + 9 = 30
4 + 5 + 6 + 7 + 8 = 30
As a function
def calculation(largest: int, number: int, target: int) -> list:
values = [x for x in combinations(range(largest + 1), number) if sum(x) == target]
print(f'number of possibilites: {len(values)}')
for x in values:
print(' + '.join(map(str, x)) + f' = {target}')
calculation(9, 5, 30)
number of possibilites: 7
0 + 6 + 7 + 8 + 9 = 30
1 + 5 + 7 + 8 + 9 = 30
2 + 4 + 7 + 8 + 9 = 30
2 + 5 + 6 + 8 + 9 = 30
3 + 4 + 6 + 8 + 9 = 30
3 + 5 + 6 + 7 + 9 = 30
4 + 5 + 6 + 7 + 8 = 30

Here's a 1-liner (not counting the import):
from itertools import combinations
print("number of possibilities ",len([s for s in combinations(range(largest_single_number+1), num_of_inputs) if sum(s)== target_sum]))
I'll leave printing the individual sets as an exercise.

I would probably use itertools.combinations
possibilities = [combo for combo in
itertools.combinations(range(largest_single_number+1), num_of_inputs))
if sum(combo) == target_sum]

Related

Sum input integer by itself, integer times

Salam, I'm given a user input that I have to sum it by itself n-times. Which means if the input is "5" for example, I should return 5 + 5 + 5 + 5 + 5 = 25
I used:
def sum(user_input):
inp_sum = 0
string = ''
for n in range(0, user_input, 1):
inp_sum += user_input
if n != user_input -1:
string+= "5 + "
else: string += '5'
return string + ' = ' + str(inp_sum)
but it returns
Failed for value=6
Expected: 6 + 6 + 6 + 6 + 6 + 6 = 36
Actual: 5 + 5 + 5 + 5 + 5 + 5 = 36
what is the solution?
You hardcoded 5 in to the logic of your function, when you should be passing in the user input to the string format logic. Also, do not name your function sum as you will shadow the built-in function sum.
def mysum(user_input):
inp_sum = 0
string = ""
for n in range(0, user_input, 1):
inp_sum += user_input
if n != user_input - 1:
string += "{} + ".format(user_input)
else:
string += str(user_input)
return "{} = {}".format(string, inp_sum)
You can simplify it like this:
def user_input(n):
return "{} = {}".format(' + '.join([str(n) for _ in range(n)]), str(n*n))
print(user_input(5))
# 5 + 5 + 5 + 5 + 5 = 25
print(user_input(6))
# 6 + 6 + 6 + 6 + 6 + 6 = 36

how to print for loop output on same line after each iteration

Code
a = int(input("enter a no"))
b = int(input("enter a range"))
for i in range(1, a+1):
print(i)
for j in range(1, b + 1):
c = i * j
print(i, "*", j, "=", c)
Desired output
1 2 3
1 * 1 = 1 2 * 1 = 2 3 * 1 = 3
1 * 2 = 2 2 * 2 = 4 3 * 2 = 6
1 * 3 = 3 2 * 3 = 6 3 * 3 = 9
1 * 4 = 4 2 * 4 = 8 3 * 4 = 12
1 * 5 = 5 2 * 5 = 10 3 * 5 = 15
1 * 6 = 6 2 * 6 = 12 3 * 6 = 18
1 * 7 = 7 2 * 7 = 14 3 * 7 = 21
1 * 8 = 8 2 * 8 = 16 3 * 8 = 24
1 * 9 = 9 2 * 9 = 18 3 * 9 = 27
1 * 10 = 10 2 * 10 = 20 3 * 10 = 30
You can tell print to finish with something other than a newline by specifying the "end" argument:
a = int(input("enter a no "))
b = int(input("enter a range "))
for i in range(1, a+1):
print(i, end=" ")
print("")
for j in range(1, b + 1):
for i in range(1, a+1):
c = i * j
print(i, "*", j, "=", c, end=" ")
print("")
In this case I split the main loop into two separate loops, the first outputs the top line (1, 2, 3...) with some large spacing, whilst the second then does all of the others with slightly less spacing.
I also switched the order of the later loops since there should be b lines, each with a multiplications, so the b loop needs to be the outer (first) loop.
In both cases an empty print statement is used to output a newline when we need it.
This is what you are looking for:
a = int(input("enter a no"))
b = int(input("enter a range"))
for i in range(1, a + 1):
print(i, end="\t"*4)
print("")
for k in range(1, b + 1):
for j in range(1, a + 1):
print(j, "*", k, "=", j*k, end="\t"*2)
print("")
You have to think line-by-line, since you cannot go back in stdout.
The first for will fill the first line
I modified your nested loop because you were using the wrong variables
"\t" is meant to get decent formatting, but it will eventually break if numbers are too big: I believe there is a more refined approach that I am not aware of
print("") is just meant to go to the next line
Approach
Approach is use f-strings to left align all the prints into fields of width 20
Use fixed field widths since otherwise columns won't line up with single and multi-digit numbers
Use print parameter end = '' to avoid carriage returns on after printing a field
Code
a = int(input("enter a no "))
b = int(input("enter a range "))
width = 20
for i in range(1, a+1):
print(f'{i:<{width}}', end="") # Print all multipliers on a single row
print("")
for j in range(1, b + 1):
# Looping over multiplication row
for i in range(1, a+1): # Looping through the columns to multipl
s = f'{i} * {j} = {i*j}' # Expression for column field
print(f'{s:<{width}}', end = '') # Print field left aligned to width 20
print("") # New row
Test
enter a no 4
enter a range 10
1 2 3 4
1 * 1 = 1 2 * 1 = 2 3 * 1 = 3 4 * 1 = 4
1 * 2 = 2 2 * 2 = 4 3 * 2 = 6 4 * 2 = 8
1 * 3 = 3 2 * 3 = 6 3 * 3 = 9 4 * 3 = 12
1 * 4 = 4 2 * 4 = 8 3 * 4 = 12 4 * 4 = 16
1 * 5 = 5 2 * 5 = 10 3 * 5 = 15 4 * 5 = 20
1 * 6 = 6 2 * 6 = 12 3 * 6 = 18 4 * 6 = 24
1 * 7 = 7 2 * 7 = 14 3 * 7 = 21 4 * 7 = 28
1 * 8 = 8 2 * 8 = 16 3 * 8 = 24 4 * 8 = 32
1 * 9 = 9 2 * 9 = 18 3 * 9 = 27 4 * 9 = 36
1 * 10 = 10 2 * 10 = 20 3 * 10 = 30 4 * 10 = 40
I corrected it like this. Thankyou guys.
just add the end="\t"*4 to fix the alignment issue.
a = int(input("enter a no "))
b = int(input("enter a range "))
for i in range(1, a+1):
print(i, end="\t"*4)
print("")
for j in range(1, b + 1):
for i in range(1, a+1):
c = i * j
print(i, "*", j, "=", c, end="\t"*2)
print("")

printing the sequence in different order

I am able to understand the logic here for the below pattern but not getting the way of implementation, please can someone help me here.
The pattern I want is like below, (in first column everything till 5, then second column after 5 leaving first and last row and so on. . )
1
2 6
3 7 9
4 8
5
Try this:
n = int(input())
for i in range(1, (n//2)+2):
for j in range(i):
print(i + ((n - 1) * j) - (j * (j - 1)) , end=' ')
print()
for i in range((n//2)+2, n + 1):
for j in range(n - i + 1):
print(i + ((n - 1) * j) - (j * (j - 1)), end=' ')
print()
Output:
n = 9
1
2 10
3 11 17
4 12 18 22
5 13 19 23 25
6 14 20 24
7 15 21
8 16
9
Logic
n = 9
1 |
2 10 |(10 - 2) = 8
3 11 17 |(11 - 3) = 8, (17 - 11) = 6
4 12 18 22 |(12 - 4) = 8, (18 - 12) = 6, (22 - 18) = 4
5 13 19 23 25 |(13 - 5) = 8, (19 - 13) = 6, (23 - 19) = 4, (25 - 23) = 2
6 14 20 24 |(14 - 6) = 8, (20 - 14) = 6, (24 - 20) = 4
7 15 21 |(15 - 7) = 8, (21 - 15) = 6
8 16 |(16 - 8) = 8
9 |
For example in line5
first number is 5 + ((n - 1) * 0) - (0 * -1) = 5
next value 5 + ((n - 1) * 1) - (1 * 0) = 13
next value 5 + ((n - 1) * 2) - (1 * 2) = 19
next value 5 + ((n - 1) * 3) - (2 * 3) = 23
next value 5 + ((n - 1) * 4) - (3 * 4) = 25
above 5 is i value and 0,1,2,3,4 are j values
generalised formula for calculating the value i + ((n - 1) * j) - (j * (j - 1))

multiplication table python nested loop not printing full table

This is my code for my multiplication table so far. I am a bit confused as to how to continue to finish this problem, basically I need to be able to print a multiplication table with this format for any number between 1 and 9:
1 2 3 4 5
--------------------------
1| 1 2 3 4 5
2| 2 4 6 8 10
3| 3 6 9 12 15
4| 4 8 12 16 20
5| 5 10 15 20 25
x = int(input("enter a number 1-9: "))
output = ""
for x in range(1 ,x+1):
output +=str(x) +"|\t"
for y in range(1,x+1):
output += str(y * x) +"\t"
output +="\n"
print(output)
You are replacing the value of x in the loop, instead you should use a different name for looping parameter:
output = ' '.join([f" {i}" for i in range(1, x+1)]) + "\n"
output += '---' * x + "\n"
for i in range(1, x+1):
output += str(i) + "| "
for y in range(1, x+1):
output += str(y * i) + " "
output += "\n"
Your loop variable should have a different name, other than x. The value of x is getting overwritten by the loop values. Your code should look like this
for i in range(1, x + 1):
output += str(i) + "| "
for y in range(1, x + 1):
output += str(y * i) + " "
output += "\n"
you have to take care also of the padding in order to have a good output, also in your first loop you have to change the name of the variable used for iteration:
x = int(input("enter a number 1-9: "))
sep = ' '
sep_len = len(sep)
output = ' ' + sep + sep.join(str(e).rjust(sep_len, ' ') for e in range(1, x + 1))
output += '\n' + '_' * len(output)
for i in range(1 , x + 1):
output += "\n" + str(i) + '|'
for y in range(1, x + 1):
output += sep + str(y * i).rjust(sep_len, ' ')
print(output)
output (for x = 5):
1 2 3 4 5
__________________________________________
1| 1 2 3 4 5
2| 2 4 6 8 10
3| 3 6 9 12 15
4| 4 8 12 16 20
5| 5 10 15 20 25

Solve equations with combinations and for loops

I have equations with multiple unknowns, and a number range:
eq1 = (x + 5 + y) #
ans = 15
no_range = [1..5]
I know that I can solve the equation by checking all possible combinations:
solved = False
for i in range(1, 5+1) # for x
for j in range(1, 5+1) # for y
if i + 5 + j == ans:
solved = True
So, the problem is that I want a function to deal with unknown_count amount of unknowns. So that both the following equations, or any, can be solved in the same manner above:
eq1 = (x + 5 + y)
ans = 15
eq2 = (x + 5 + y + z * a + 5 * b / c)
ans = 20
I just cannot think of a way, since for each unknown you need a for loop.
You could use itertools.product to generate the Cartesian product for an
arbitrary number of variables:
In [4]: import itertools
In [5]: list(itertools.product(range(1, 5+1), repeat=2))
Out[5]:
[(1, 1),
(1, 2),
(1, 3),
...
(5, 3),
(5, 4),
(5, 5)]
So you could modify your code like this:
import itertools as IT
unknown_count = 6
ans = 20
solved = False
def func(*args):
x, y, z, a, b, c = args
return x + 5 + y + z * a + 5 * b / c
for args in IT.product(range(1, 5+1), repeat=unknown_count):
if func(*args) == ans:
solved = True
print('{} + 5 + {} + {} * {} + 5 * {} / {} = {}'.format(*(args+(ans,))))
which yields a lot of solutions, such as
1 + 5 + 1 + 1 * 3 + 5 * 2 / 1 = 20
1 + 5 + 1 + 1 * 3 + 5 * 4 / 2 = 20
1 + 5 + 1 + 2 * 4 + 5 * 1 / 1 = 20
...
5 + 5 + 5 + 2 * 2 + 5 * 1 / 5 = 20
5 + 5 + 5 + 3 * 1 + 5 * 2 / 5 = 20
5 + 5 + 5 + 4 * 1 + 5 * 1 / 5 = 20
The * unpacking operator was used
to create a function, func, which accepts an arbitrary number of arguments (i.e. def func(*args)), and also to
pass an arbitrary number of arguments to func (i.e. func(*args)).

Categories

Resources