Python: keep the number in a specific range - python

I have a problem that runs like this:
I have an integer n, let n = 30.
I add n with another integer k. Say, k = 19
However, I want to keep n between x and y, say 20 and 35. So if n+k > 35 it jumps back to 20 at 36, then continue to add 13 (19-6=13), which the final answer is 33.
I have already done the problem from scratch, and it's lengthy. It looks like this:
def plus(n,k,x,y):
result= n+k
if result > y: #do sth
if result < x: #do sth
return result
My question is, is there any build-in method, in any library, that helps me to do this problem? Thanks a lot.

The modulo operator % performs the kind of wrapping you're looking for. a % b gives the remainder from dividing a by b, resulting in the following wraparound pattern:
>>> for i in range(-2, 12):
... print(f"{i} % 5 = {i % 5}")
...
-2 % 5 = 3
-1 % 5 = 4
0 % 5 = 0
1 % 5 = 1
2 % 5 = 2
3 % 5 = 3
4 % 5 = 4
5 % 5 = 0
6 % 5 = 1
7 % 5 = 2
8 % 5 = 3
9 % 5 = 4
10 % 5 = 0
11 % 5 = 1
(The results you see with a negative left operand aren't what you get in most languages. Most languages would give you -2 and -1 instead of 3 and 4, but the 3 and 4 answers turn out to be more useful.)
You want to stay in a range from x to y inclusive instead of 0 to y-1, so we need to add and subtract x to adjust the range % gives us:
def plus(n,k,x,y):
modulus = y-x+1
return (n+k-x) % modulus + x
Sample output:
>>> plus(30, 19, 20, 35)
33
>>> plus(30, 0, 20, 35)
30
>>> plus(30, 5, 20, 35)
35
>>> plus(30, 6, 20, 35)
20
>>> plus(30, -10, 20, 35)
20
>>> plus(30, -11, 20, 35)
35

You’re looking for the modulo operator: %
result = x + (n + k - x) % (y - x + 1)

After reading your response, you can try that loop
def plus(a, b, minvalue, maxvalue):
plusresult = a + b
while plusresult > maxvalue:
plusresult -= maxvalue - minvalue
return max(plusresult, minvalue)

Related

Compacting Number values into shorter string

I have 1296 random values ranging 0-31. I want to represent this information so let’s say I just concatenate all 1296 values into a string. If I were to do that the string would be about 2500 characters long. How can I store this information in a shorter string so I can still know all 1296 values in the correct order but not have such a long string? (I managed to get it to 648, but wanted to see if someone has an even better way)
This will work when the range of numbers in the input list are 0-31 (inclusive) and when the list length is a multiple of 3
import random
numbers = [random.randint(0, 31) for _ in range(1296)]
def pack(n):
result = []
for i in range(0, len(n), 3):
result.append(n[i] << 10 | n[i+1] << 5 | n[i+2])
return ''.join(map(chr, result))
def unpack(s):
result = []
for o in map(ord, s):
for shift in 10, 5, 0:
result.append(o >> shift & 0x1F)
return result
packed = pack(numbers)
print(len(packed))
result = unpack(packed)
assert result == numbers
Output:
432
Note:
If the range of numbers was 1-31 then this technique (with a minor modification) could be used for any list length because zero could be used as a padding indicator as follows:
import random
numbers = [random.randint(1, 31) for _ in range(1295)]
def pack(n):
result = []
a = None
for i, x in enumerate(n):
match i % 3:
case 0:
a = x << 10
case 1:
a |= x << 5
case _:
result.append(a|x)
a = None
if a is not None:
result.append(a)
return ''.join(map(chr, result))
def unpack(s):
result = []
for o in map(ord, s):
for shift in 10, 5, 0:
if (n := o >> shift & 0x1F) == 0:
break
result.append(n)
return result
packed = pack(numbers)
print(len(packed))
result = unpack(packed)
assert result == numbers
You can easily store 32 unique values in one character, which means your 1296 numbers can fit in a string of 1296 characters.
For example:
import random
numbers = [random.randint(0, 31) for i in range(1296)]
def numbers_to_string(numbers):
return "".join(chr(ord("0") + number) for number in numbers)
def numbers_from_string(string):
return [ord(char) - ord("0") for char in string]
numbers_str = numbers_to_string(numbers)
numbers_roundtrip = numbers_from_string(numbers_str)
print(numbers_roundtrip == numbers)
Output:
True
These are the numbers and the characters used to represent them:
0 0
1 1
2 2
3 3
4 4
5 5
6 6
7 7
8 8
9 9
10 :
11 ;
12 <
13 =
14 >
15 ?
16 #
17 A
18 B
19 C
20 D
21 E
22 F
23 G
24 H
25 I
26 J
27 K
28 L
29 M
30 N
31 O

Find Python Multiplication from user input

Junior Python Coder here! Trying to print multiplication table with user input but stuck.
min_num=1
max_num=11
starting_range = int(input ("Enter the minimum number: "))
ending_range = int(input ("Enter the maximum number: "))
print ("The Multiplication Table of: ", starting_range)
for count in range(1, 11):
print (starting_range, 'x', count, '=', ending_range * count)
if max_num - min_num > 10 :
print('invalid range ')
else:
for num in range (min_num,max_num):
print ("The Multiplication Table of: ", ending_range)
for count in range(min_num, max_num):
print (starting_range, 'x', count, '=', ending_range * count)
I'm not sure I really understand what you're trying to do as your code isn't formatted, but for a multiplication table, a nested loop is a solution.
The basic idea is: For every number in the given range, loop over the whole range and multiply it by each element. This will print the whole multiplication table.
start = 1 # You can change these to be inputted by the user.
end = 10
for i in range(start, end + 1): # We add 1 to the end because range() is exclusive on endpoint.
for j in range(start, end + 1):
print(f"{i} x {j} = {i * j}")
If you only need the table as something like:
15 x 1
15 x 2
15 x 3
...
You can do this with one loop:
num = 10
for i in range(1, num + 1):
print(f"{num} x {i} = {num * i}")
I recommend you search up on F-strings in Python if you do not understand the print(f"..") parts. They're very convenient. Good luck!
Minimal change to original code:
min_num = 1
max_num = 11
starting_range = 4 # You can use int() and input() as in your original code to make this user defined.
ending_range = 7
# Removed the error checking, wasn't sure precisely what it was meant to do.
for num in range(starting_range,ending_range):
print ("The Multiplication Table of: ", num)
for count in range(min_num, max_num):
print (num, 'x', count, '=', num * count)
Try it at https://www.mycompiler.io/view/7JVNtxkT53k
This prints:
The Multiplication Table of: 4
4 x 1 = 4
4 x 2 = 8
4 x 3 = 12
4 x 4 = 16
4 x 5 = 20
4 x 6 = 24
4 x 7 = 28
4 x 8 = 32
4 x 9 = 36
4 x 10 = 40
The Multiplication Table of: 5
5 x 1 = 5
5 x 2 = 10
5 x 3 = 15
5 x 4 = 20
5 x 5 = 25
5 x 6 = 30
5 x 7 = 35
5 x 8 = 40
5 x 9 = 45
5 x 10 = 50
The Multiplication Table of: 6
6 x 1 = 6
6 x 2 = 12
6 x 3 = 18
6 x 4 = 24
6 x 5 = 30
6 x 6 = 36
6 x 7 = 42
6 x 8 = 48
6 x 9 = 54
6 x 10 = 60
Alternative code defining a function:
def print_multiplication_table(n, max_value=11):
if n > max_value or n <= 0:
raise ValueError
print(f"The Multiplication Table of: {n}")
for m in range(1, max_value):
print(f"{n} x {m} = {n*m}")
starting_range = 4 # You can use int() and input() as in your original code to make this user defined.
ending_range = 7
for i in range(starting_range, ending_range):
print_multiplication_table(i)
Try it at https://www.mycompiler.io/view/1uttFLmFEiD

How to generate a combination of two numbers that equal a given input

I am trying to generate a combination of two numbers using only 5 and 7 that will equal the sum of any given input. The input range is 24:1000. What I've done so far is determine if the input is divisible by 5 or 7 and then generate a list whose sum equals the input.
Here is my working example:
def change(amount):
if amount not in range(24,1001):
print("The number is outside the range.")
else:
remainder=amount%5
if remainder==0:
n = int(amount/5)
array=[0 for i in range(n)]
for i in range(n):
array[i]=5
return array, sum(array)
else:
remainder=amount%7
if remainder==0:
n = int(amount/7)
array=[0 for i in range(n)]
for i in range(n):
array[i]=7
return array, sum(array)
else:
# here is where am stuck
print(change(28))
The output needs to be in the form of an array. For example: for change(24), the array should be [5,5,7,7].
Most simplistic approach I could think of
def change(target):
if target not in range(24,1001):
raise ValueError("The number is outside the range.")
res = []
while target % 5 != 0:
res.append(7)
target -= 7
while target != 0:
res.append(5)
target -= 5
return res
change(28)
>>> [7, 7, 7, 7]
You don't need loops for this, just a little bit of algebra. See the comments for details.
def change(amount):
if not 24 <= amount <= 1000:
print("The number is outside the range.")
return None
# 5*3 - 7*2 = 1, so 5*(3*n) + 7*(-2*n) = n, and therefore
# 5*(3*n - 7*k) + 7*(5*k - 2*n) = n for all k
# We want to find a small k so that the terms in each bracket are positive
k = 3 * amount // 7
x = 3 * amount - 7 * k
y = 5 * k - 2 * amount
return x, y, [5] * x + [7] * y
# Print the sequences for some small amounts
for i in range(24, 70):
x, y, seq = change(i)
print(i, x, y, sum(seq) == i)
# Check all values in the range
for i in range(24, 1001):
x, y, seq = change(i)
assert sum(seq) == i
print('ok')
output
24 2 2 True
25 5 0 True
26 1 3 True
27 4 1 True
28 0 4 True
29 3 2 True
30 6 0 True
31 2 3 True
32 5 1 True
33 1 4 True
34 4 2 True
35 0 5 True
36 3 3 True
37 6 1 True
38 2 4 True
39 5 2 True
40 1 5 True
41 4 3 True
42 0 6 True
43 3 4 True
44 6 2 True
45 2 5 True
46 5 3 True
47 1 6 True
48 4 4 True
49 0 7 True
50 3 5 True
51 6 3 True
52 2 6 True
53 5 4 True
54 1 7 True
55 4 5 True
56 0 8 True
57 3 6 True
58 6 4 True
59 2 7 True
60 5 5 True
61 1 8 True
62 4 6 True
63 0 9 True
64 3 7 True
65 6 5 True
66 2 8 True
67 5 6 True
68 1 9 True
69 4 7 True
ok
This doesn't necessarily give the shortest sequence for every amount, but it's usually close to the optimum, and it's not too hard to modify this code to get the optimum. But that will be left as an exercise for the reader. ;)
To learn more about this technique, please see the Wikipedia article on linear Diophantine equations.
This is the fastest I could think of, as it only uses a single while cycle.
def change(amount):
if not 24 <= amount <= 1001:
print('{} is outside range'.format(amount))
return
sevens = []
fives, remainder = divmod(amount, 5)
while remainder:
amount -= 7
sevens.append(7)
fives, remainder = divmod(amount, 5)
return [5] * fives + sevens
PS: please don't mix tabulations sizes :-)
For all combinations here is an idea. The loops can be optimise further
import itertools
def change(target):
nums = [5, 7]
min_len = int(target / 7)
max_len = int(target / 5) + 1
res = []
for len_ in range(min_len, max_len):
r = itertools.combinations_with_replacement(nums, len_)
for item in r:
if sum(item) == target:
res.append(item)
return res
And a little bit optimised one. Collect all combinations within the possible range and filter out the ones with sum == target.
import itertools
def change(target):
nums = [5, 7]
min_len = int(target / 7)
max_len = int(target / 5) + 1
res = []
for len_ in range(min_len, max_len):
res += (list(itertools.combinations_with_replacement(nums, len_)))
return list(filter(lambda x: sum(x) == target, res))
The output which contains all possible combinations for target = 70
[(7, 7, 7, 7, 7, 7, 7, 7, 7, 7), (5, 5, 5, 5, 5, 5, 5, 7, 7, 7, 7, 7), (5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5)]
Without any loop in FP style. Reducing all possible combinations into one list and filter the correct elements of this list in return.
import itertools
from functools import reduce
def change(target):
nums = [5, 7]
min_len = int(target / 7)
max_len = int(target / 5) + 1
res = reduce(lambda x, y:
x + (list(itertools.combinations_with_replacement(nums, y))),
range(min_len, max_len), [])
return list(filter(lambda x: sum(x) == target, res))

python - adding each digit that is greater than 4

Given an integer. for each individual digit that is greater than 4, i need to add it to all the next digits that greater than 4.
For example: a = 4567; the result should be 0 + (5) + (5+6) + (5+6+7) = 34
So far in my code, I was able to get the sum for single digit only. If the integer is greater 10, it will only give the sum of the very first digit. Any idea why this happening?
def morethanfour(number):
num = 0
num = [int(d) for d in str(number)] #seperate into individual digit
total = 0
for i in range (len(num)):
if num[i] > 4:
total = sum(x for x in range(5, num[i]+1)) #adding the sum
return total
num = 9
print(morethanfour(num))
the result when num = 9 is 35 (5+6+7+8+9)
However, when num = 178, it gave me 0
Try this:
>>> def morethanfour(number):
return sum(sum(range(5,x+1)) for x in map(int,str(number)) if x>4)
>>> morethanfour(9)
35
>>> morethanfour(4567)
34
>>> morethanfour(178)
44
>>> sum(sum(num[j] for j in range(0, i+1) if num[j] > 4) for i in range(len(num)))
34

How can I used nested loops to print a matrix of numbers in Python?

For instance, if I have a function and say the input is a number n (i.e. 5)
I want a 5x5 matrix thats like:
1 2 3 4 5
2 10
3 15
4 20
5 10 15 20 25
and how can I write this if I only want the outer most square or the inner most?
(This is for python)
What I tried:
def f4(n):
for i in range(1, n):
for j in range(1, n):
print i*j,
print
To control spacing in strings, try str.format. For example:
>>> print '{:2} {:2} {:2} {:2} {:2}\n{:2} {:2} {:2} {:2} {:2}'.format(1, 2, 3, 4, 5, 10, 20, 30, 40, 50)
1 2 3 4 5
10 20 30 40 50
Another hint: it looks like you have 2 types of rows- top/bottom rows and middle rows. The top/bottom rows have a similar format that's different from the middle rows, which are themselves similar.
My solution
% cat squar.py
def squarpy(n, length=5):
fmt = "%%%dd"%(length)
sp = " "*length
square = " ".join([fmt%(i+1) for i in range(n)])
for j in range(2,n):
row = " ".join([fmt%(i*j+j) if i==0 or i==n-1 else sp for i in range(n)])
square = square +"\n" + row
tail = " ".join([fmt%(i*n+n) for i in range(n)])
square = square + "\n" + tail
return square
print squarpy(3)
print
print squarpy(5)
% python2 squar.py
1 2 3
2 6
3 6 9
1 2 3 4 5
2 10
3 15
4 20
5 10 15 20 25
%

Categories

Resources