Need explanation of how function works printing digits in reverse - python

I cheated after giving up of how to figure out how to print digits backwards making a function for it but I still do not quite understand how it works. For instance why does it print the digits backwards and not in order?
def print_digits(n):
"""
>>> print_digits(13789)
9 8 7 3 1
>>> print_digits(39874613)
3 1 6 4 7 8 9 3
>>> print_digits(213141)
1 4 1 3 1 2
"""
while n > 0:
print n % 10
n = n / 10
I would appreciate a line by line explanation starting with the while loop. I've tried tracing it in my head and on paper but just can't grasp the code in the function.

In the first line in the loop the '%' operator devides the number given by 10 and returns the rest only, means the fraction of the division (25 : 10 = 2.5, so it returns the 5 only!).
The line 'n/10' then does exactly the other way around and stores part left of the comma into the variable itself, as the '/' operator returns only the left part of the comma.
In short you can say:
n%10 returns only the rest of the divison
n/10 "throws" the rest of the division away
the code repeats

% operator returns the remainder of division. (20%3=2,24%5=4).
When you divide a number by 10 remainder is always the last digit.
For example 123/10=12 & remainder is 3. So 123%10=3.
Inside the while loop while n is greater than 0 the last digit of n is printed.
And because of the line n=n/10, n becomes n/10. Here integer division has used so finally value of n will become 0 and then the loop will stop.( if n is initially 123 value of n will change as 123,12,1,0 and then loop will stop.)

Related

Python: What does 'and not' mean in this code [duplicate]

This question already has answers here:
What is Truthy and Falsy? How is it different from True and False?
(8 answers)
Closed 3 years ago.
This is the entire code. What does 'and not' mean in the code. I understand it to mean that only a number that will equal to 0 when the number modulus 2 is carried out.
That is if 10 is entered by the user, 2,4,6,8 will be sum to get 20.
the_max = int(input("Enter the upper limit:"))
the_sum = 0
extra = 0
for number in range(1,the_max):
if number%2 and not number%3:
the_sum = the_sum + number
else:
extra = extra + 1 # Line 1
print(the_sum) # Line 2
print(extra) # Line 3
It means that the number is not a multiple of 2 but a multiple of 3;
the if statement has two conditions:
number % 2
since the % returns the remainder of a a number divided by 2, it will return 0 on a multiple of 2 and will result in rejection of if condition.
and not number % 3
This means that we need both condition to be good. But with this one the not operand reverses it.
So this time any number % 3 in which number is a multiple of 3 will result in 0 and will be reversed to 1;
You're parsing it wrong. The correct interpretation is
if (number % 2 != 0) and (number % 3 == 0):
This code is taking shortcuts by omitting the explicit comparison to zero, since 0 evaluates to False in a boolean expression like this one, whereas any other integer value evaluates to True.
The second clause, thus, is given a not to flip its polarity. not (number % 3) is equivalent to (number % 3 == 0).

Find the number of substrings of a string which can be divisible by a number k

given a string, I want to find all the sub-strings which can be formed from the original string which are divisible by an integer k. For example the string 14917 can form 7 sub-strings which are divisible by the integer 7. The sub-strings are: 14, 1491, 14917, 49, 91, 917 and 7. I have come up with a solution but it does not run efficiently when a large string is inputted. My code is
string = '14917'
divider = 7
count = 0
for i in range(len(string)):
for j in range(i+1, len(string)+1):
sub_string = string[i:j]
if int(sub_string) % divider == 0:
count += 1
print(count)
I have read about fast approaches for this kind of a problem, most of which talked about computing the rolling remainders of the string but I could not really implement it correctly. Is there any way in which this problem can be solved quickly. Thanks in advance.
Here is an outline of how to solve this problem if we just want the count, we don't mind that there are multiple ways of pulling the same substring out, and k is relatively prime to 10 (which 7 is).
First let's go from the last digit of our number to the first, keeping track of the remainder of the whole number. In the case of 14917 that means compiling the following table:
number 10**digits % 7 digit remainder
0
7 1 7 0+1*7 -> 0
17 3 1 0+3*1 -> 3
917 2 9 3+2*9 -> 0
4917 6 4 0+6*4 -> 3
14917 4 1 3+4*1 -> 0
Now here is the trick. Whenever you see the same remainder in two places, then from one to the other you've got something divisible by 7. So, for example, between the two 3's you get 49. If a particular value appears i times, then that represents i*(i-1)/2 (possibly identical) substrings that are divisible by 7.
If we want to get unique substrings, then we have to do a lot more work. But we can still be O(length of string) if we generate a suffix tree so that we can count the duplicates relatively quickly.
To actually produce the numbers, this approach will still be O(n^2). But it will be faster than your existing approach for large strings because you're only ever doing math with small integers. Converting to/from strings to numbers that are thousands of digits long is not particularly fast...
So here is more detail on the complications of the suffix tree approach for count of unique substrings. It is a lot harder to get right.
Above we proceeded from the end of the string back to the beginning, keeping track of the final remainder. But this means that what a particular digit adds to the remainder depends on its position in the string. However in a tree a given node is at different height's from the ends of the string. This makes the remainder at a particular node harder to calculate.
What we need to do is calculate some sort of remainder where the contribution of the current digit depends on its height, to instead keep the contribution of the current digit fixed. The trick to that is to multiply the set of possible remainders bubbling up by 10-1 instead. Then we'll get 0s if and only if the number starting here is divisible by k. What does 10-1 (mod k) mean? It means a number m such that (10*m) % k is 1. It can be seen by inspection that 5 works for 7 because 50 = 7*7 + 1. We can always find the inverse with trial and error. In general its existence and value can be more efficiently determined through Euler's Theorem. Either way, in our case it is 5.
Now it is more work to multiply the set of remainders by a number instead of the current digit, but it has the advantage that doing this we can merge branches of a tree. Consider, for example, a suffix tree for 5271756. (Note that uniqueness matters because the string 7 appears twice.)
(root):
a
b
c
d
e
(a): '17'
f
(b): '27'
a
(c): '5'
b
e
(d): '7'
a
f
(e): '6'(end)
(f): '5'
e
Now we can work our way back up the tree finding counts of remainders. The calculation for 756 illustrates the idea:
digit prev_remainders remainders
# for 6
6 {} {(6)%7: 1}
# for 5 56
5 {6: 1} {(5)%7: 1, (5+5*6)%7: 1}
{ 5: 1, 0: 1} = {0:1, 5:1}
# for 7 756 75
7 {0: 1, 2:1} {(7)%7: 1, (7+5*0)%7: 1, (7+5*5): 1}
{ 0: 1, 0: 1, 4: 1} = {0:2, 4:1}
And so at that point we have 2 strings divisible by 0 starting there, namely 7 and 756.
Filling out the whole tree starting from the root and bubbling back in the same way (done by hand, I could make mistakes - and made a lot of them the first time around!):
(root): {0:8, 1:6, 2:3, 4:1, 5:4, 6:4}
a
b
c
d
e
(a): '17' {0:1, 1:3}
f
(b): '27' {2:3, 6:3}
a
(c): '5' {0:4, 1:3, 5:1}
b
e
(d): '7' {0:3, 4:1, 5:3}
a
f
(e): '6'(end) {6:1}
(f): '5' {0:1, 5:1}
e
From which we conclude that there are 8 substrings divisible by 7. In fact they are:
175 (af)
5271 (cba)
52717 (cbaf)
5271756 (cbafe)
56 (ce)
7 (d)
7175 (daf)
756 (dcf)
What about the rest? What does it mean that, for example, there are 3 ways of getting 2? It means that there are 3 substrings s such that ( (s%7) * (5^(len(s)-1)) ) %7 == 2. So we didn't need that in our final answer, but we certainly did in the intermediate calculations!

loop numbers down and up and not using recursion in python

I have a small problem with my code. I can't seem to figure out how to do this. I can get it to work with two for loops. But in the exercise it says that i only can use one loop to get the result.
The code is supposed to execute this:
bounce2(4):
4
3
2
1
0
1
2
3
4
What I have come up with:
def bounce2(n):
for x in range(n,-1,-1):
print(x)
Which prints out 4,3,2,1,0
But now i dont know what to do..
I have tried different if statements such as:
def bounce2(n):
for x in range(n,-1,-1):
print(x)
if n == 0:
x = x + 1
print(x)
But they only print one integer because they are out of the loop.
Same thing goes if i try to make the if-statement inside the loop, then it prints out something like 433221100. I dont know how to get the numbers to switch places. The print statement should also be an integer and not a string. So i can't use replaced.
Really need help to figure out the logic. All help is appreciated.
So, a little bit of my thought process before showing you the code. Clearly there are nine lines, or more generally n * 2 + 1 lines. Because we need to count down to 0 and back up. That's how many times you need to call print.
Now, if you add line numbers to the expected output and think of it as a table describing a function f(i, n) where i is the line number, and n is the starting and ending value. what is f? Can you write down the formula? e.g.
i f(i, 4)
0 4
1 3
2 2
3 1
4 0
5 1
6 2
7 3
8 4
We can write down the basic structure of the code, we still don't know what f look like but assume we have it:
for i in range(2*n+1):
print f(i)
And, what is f? Now you need to be a little creative and maybe experiment a bit. What I did was to try basic arithmetic combinations of i and n to match f(i, n), and I quickly noticed that n - i works until we reach the second half of the output, which only differs by a - sign.
i f(i, 4) n - i
0 4 4
1 3 3
2 2 2
3 1 1
4 0 0
5 1 -1
6 2 -2
7 3 -3
8 4 -4
Soooo, take the absolute value of n - i or i - n, whatever.
def f(i, n):
return abs(n-i)
Here is what I believe to be a pretty elegant solution:
def bounce(n):
for x in range(-n, n+1):
print(abs(x))
Our loop goes from the negative of n to the positive of n, printing the absolute value.
Since you need to count n times downwards, and another n times upwards, and 1 comes from counting 0, instead of actually counting downwards and then upwards in two separate loops, we can use one loop to count upwards 2 * n + 1 times, which effectively is like counting towards n and then bouncing off n, so we can simply calculate the "distance" to n instead, which is the absolute value of n - x:
def bounce2(n):
for x in range(2 * n + 1):
print(abs(n - x))
so that bounce2(4) would output:
4
3
2
1
0
1
2
3
4
a very simple solution will be:
for i in range(n, -(n+1), -1):
print(abs(i))
this like mirroring numbers around some point.
in your case that point is zero and to have identical mirroring use abs
Try the below, have a list l with a element of str(n) iterate trough the range of n times 2, then check x is bigger than n+2 if it is add 1 to n, otherwise subtract 1 from n, both cases append to l, then at the end, do str.join to join '\n' (newline) with l:
def bounce2(n):
l=[str(n)]
for x in range(n*2):
if x>n+2:
n+=1
l.append(str(n))
else:
n-=1
l.append(str(n))
return '\n'.join(l)
print(bounce2(4))
Output:
4
3
2
1
0
1
2
3
4

Getting the number of digits of nonnegative integers (Python) [duplicate]

This question already has answers here:
How to find length of digits in an integer?
(31 answers)
Closed 6 years ago.
The question asks:
<< BACKGROUND STORY:
Suppose we’re designing a point-of-sale and order-tracking system for a new burger
joint. It is a small joint and it only sells 4 options for combos: Classic Single
Combo (hamburger with one patty), Classic Double With Cheese Combo (2 patties),
and Classic Triple with Cheese Combo (3 patties), Avant-Garde Quadruple with
Guacamole Combo (4 patties). We shall encode these combos as 1, 2, 3, and 4
respectively. Each meal can be biggie sized to acquire a larger box of fries and
drink. A biggie sized combo is represented by 5, 6, 7, and 8 respectively, for the
combos 1, 2, 3, and 4 respectively. >>
Write an iterative function called order_size which takes an order and returns the number of combos in the order. For example, order_size(237) -> 3.
Whereby I should have
order_size(0) = 0
order_size(6) = 1
order_size(51) = 2
order_size(682) = 3
My code is:
def order_size(order):
# Fill in your code here
if order > 0:
size = 0
while order > 0:
size += 1
order = order // 10
return size
else:
return 0
But I don't get the order // 10 portion. I'm guessing it's wrong but I can't think of any stuff to substitute that.
No need for iterative function, you can measure the length of the number by "turning" it into a string:
num = 127
order = len(str(num))
print(order) # prints 3
But if you really want to do it iteratively:
def order(num):
res = 0
while num > 0:
num = int(num / 10)
res += 1
return res
print(order(127)) # prints 3
How about this:
from math import log
def order_size(order):
if order <= 0: return 0
return int(log(order, 10) + 1)
Some samples (left column order, right column order size):
0 0
5 1
10 2
15 2
20 2
100 3
893 3
10232 5
There are a couple errors in your suggested answer.
The else statement and both return statements should be indented a level less.
Your tester questions indicate you are supposed to count the digits for nonnegative integers, not just positive ones (i.e. you algorithm must work on 0).
Here is my suggested alternative based on yours and the criteria of the task.
def order_size(order):
# Fill in your code here
if order >= 0:
size = 0
while order > 0:
size += 1
order = order // 10
return size
else:
return 0
Notice that
By using an inclusive inequality in the if condition, I am allowing 0 to enter the while loop, as I would any other nonnegative single digit number.
By pushing the first return statement back, it executes after the while loop. Thus after the order is counted in the variable size, it is returned.
By pushing the else: back, it executes in the even the if condition is not met (i.e. when the numbers passed to order_size(n) is negative).
By pushing the second return back, it is syntactically correct, and contained in the else block, as it should be.
Now that's taken care of, let me address this:
But I don't get the order // 10 portion.
As of Python 3, the // is a floor division (a.k.a integer division) binary operation.
It effectively performs a standard division, then rounds down (towards negative infinity) to the nearest integer.
Here are some examples to help you out. Pay attention to the last one especially.
10 // 2 # Returns 5 since 10/2 = 5, rounded down is 5
2 // 2 # Returns 1 since 2/2 = 1, rounded down is 1
11 // 2 # Returns 5 since 11/2 = 5.5, rounded down is 5
4 // 10 # Returns 0 since 4/10 = 0.4, rounded down is 0
(-4) // 10 # Returns -1 since (-4)/10 = -0.4, rounded down is -1
For nonnegative numerator n, n // d can be seen as the number of times d fits into n whole.
So for a number like n = 1042, n // 10 would give you how many whole times 10 fits into 1042.
This is 104 (since 1042/10 = 104.2, and rounded down we have 104).
Notice how we've effectively knocked off a digit?
Let's have a look at your while loop.
while order > 0:
size += 1
order = order // 10
Every time a digit is "knocked off" order, the size counter is incremented, thus counting how many digits you can knock off before you hit your terminating step.
Termination occurs when you knock of the final (single) digit. For example, say you reduced order to 1 (from 1042), then 1 // 10 returns 0.
So once all the digits are "knocked off" and counted, your order will have a value of 0. The while loop will then terminate, and your size counter will be returned.
Hope this helps!
Disclaimer: Perhaps this isn't what you want to hear, but many Universities consider copying code from the Internet and passing it off as your own to be plagiarism.

Checking to see if a number ends in 5?

I'm trying to define a function that takes 2 parameters, adds them up, and if the sum of the two parameters ends in 5, it reports a 2. If it doesn't end in 5, it returns 8.
Any ideas?
I was thinking of doing an if statement, but I'm confused as to how I would check if a number ends in 5( or is 5).
Thanks for your help, trying to teach myself how to program is so difficult yet so rewarding :)
Solution
My answer assumes you are checking integers (which seems pretty reasonable judging from your question):
def sum_ends_with_5(a, b):
"""
Checks if sum ends with "5" digit.
"""
result = a + b
return 2 if result % 10 == 5 else 8
or more flexible (with any number of arguments):
def sum_ends_with_5(*args):
"""
Checks if sum ends with "5" digit.
"""
result = sum(args)
return 2 if result % 10 == 5 else 8
How it works (aka tests)
The function behaves like that:
>>> sum_ends_with_5(5)
2
>>> sum_ends_with_5(3)
8
>>> sum_ends_with_5(2, 8)
8
>>> sum_ends_with_5(7, 8)
2
>>> sum_ends_with_5(10, 20, 3, 2)
2
Shorter version
So, if you want to write it in shorter and more flexible way, you can do this:
def sum_ends_with_5(*args):
return 2 if sum(args) % 10 == 5 else 8
Take the modulus by 10 and check if it's 5.
print num % 10 == 5
Numbers end in 5 if and only if they are are divisible by 5 but are not divisible by 10. You can easily check for these conditions with modulo arithmetic. More generally, you can check if a number ends with a digit by comparing the mod 10 value of that number to the digit.
num = 1234
isDivisibleByFive = num % 10 == 5
One easy approach is to take the number and convert it to a string and check the last digit using indexing to see if it is 5:
E.g.,
n = 153
str(n)[-1] == '5':
False
and
n = 155
str(155)[-1] == '5'
True
So as part of an if-statement:
if str(n)[-1] == `5`:
print "number ends in 5"
else:
print "number did not end in 5"
If you just wanted to check for divisibility by 5 (which is different than ending with 5) you could use the mod operation.
But you also could mod by 10 and check for a remainder of 5 to determine if the number (int) ends with 5. My solution checks for the last digit of any number (including floats)
I like the solution from Tadeck best but there is another way, not as good in my opinion for this specific use case, but still may be useful if your return values ever need to follow more complex rules than is available from a simple modulo operation.
def xlatVal (*nums):
# 0 1 2 3 4 5 6 7 8 9
lookupTbl = [8,8,8,8,8,2,8,8,8,8]
return lookupTbl[sum(nums) % 10]
While the values are still reduced to a range using modulo, this allows arbitrary translations across that range.
Convert it to a string and check the last character:
str(num)[-1] == "5"

Categories