simple for loop needing explained - python

I know this is going to sound silly but I cannot for the life of me figure out the logic behind how this for loop returns 13,11,9,7.
for i in range(13,5,-1):
if i % 2 != 0:
print i
I know the first value is the number it starts with, the second is where it stops, and the third being the steps it takes. The "if i % 2 !=0:" is what is throwing me off. Can anybody explain what is happening for me?

the first bit is the range(13,5,-1) which just counts backwards from 13 to 6. The next bit is i%2 != 0. i%2 == 0 is equivalent to saying if even, or "if this number can be divided by 2 with no remainder", so your statment is saying "if odd" (which is obviously the same as "if not even").
Basically, the loop is printing odd numbers starting at 13 and decreasing down to 6 (but 6 is even, so it doesn't get printed)

% is the modulo operator. From the docs:
The % (modulo) operator yields the remainder from the division of the
first argument by the second. The numeric arguments are first
converted to a common type. A zero right argument raises the
ZeroDivisionError exception. The arguments may be floating point
numbers, e.g., 3.14%0.7 equals 0.34 (since 3.14 equals 4*0.7 + 0.34.)
The modulo operator always yields a result with the same sign as its
second operand (or zero); the absolute value of the result is strictly
smaller than the absolute value of the second operand.

if i % 2 !=0
That line means "if the remainder after dividing i by 2 is not equal to 0," so it's checking to see if i is odd. The for loop is counting down by 1, but the if statement skips printing the even numbers.

Related

Debugging in Hungarian Maximum Matching

I wrote a code to solve the following algorithm question:
Given a number of positive integers all larger than 1, find the maximum number of pairs whose sum is a prime number. The number of positive integers is always an even number.
For example, given 2 5 6 13 2 11, the answer is 3 since 2+5=7, 6+13=19, 2+11=13.
I wrote the following code to solve the problem. I know this is not the optimal algorithm, but I just cannot find the bug in it that results in my failure in test cases.
def _isPrime(num):
for i in range(2, int(num**0.5)+1):
if num % i==0:
return False
return True
def findPairs(odds, evens, pairDict):
if len(odds)==0 or len(evens)==0:
return 0
key=' '.join(list(map(str, odds+evens)))
if key in pairDict:
return pairDict[key]
n=0
for i in range(len(evens)):
newOdds=odds.copy()
newEvens=evens.copy()
del newOdds[0]
del newEvens[i]
if _isPrime(odds[0]+evens[i]):
n=max(n,findPairs(newOdds, newEvens, pairDict)+1)
else:
n=max(n,findPairs(newOdds, newEvens,pairDict))
pairDict[key]=n
return n
numbers=list(map(int,input().split()))
odds=[i for i in numbers if i%2==1]
evens=[j for j in numbers if j%2==0]
pairDict={}
print(findPairs(odds,evens,pairDict))
Can someone help me find where the problem is. Thanks a lot!
The problem is that the recursion always tries to match the first odd number with some even number. This can go wrong if there are fewer even numbers than odd numbers because it will use up an even number that could have been used for a later match.
For example, consider "13 2 3". This code will return 0, but 2+3 is a prime.
You could fix it by also allowing an extra recursion case where the first odd number is discarded without reducing the even list.
del newOdds[0]
n=max(n,findPairs(newOdds, newEvens, pairDict)) # added line
del newEvens[i]

Python homework regarding prime numbers

My homework is simple, declare a function named printPrimeNumbersTo with a single argument named to
I created the skeleton of the code itself, however, I needed some help from the net.
GeeksforGeeks was the site where I "borrowed" a line of code, which I don't completely understand. (Site: https://www.geeksforgeeks.org/python-program-to-print-all-prime-numbers-in-an-interval/)
My code looks like this (I have comments on nearly every line, describing what I think that the line of code does):
def printPrimeNumbersTo(to):
x = 0
prime_list = [] # This was a string, however, I changed it to a list so I won't have to convert the numbers to a string every time I wanted to append it to the list
for i in range(x, to + 1): # Create a for loop, using the function range an starting the loop at number 0. Add 1 to 'to', because range excludes the end integer
if i == 0 or i == 1:
continue
else:
for j in range(2, i // 2 + 1): # <--
if i % j == 0: # If 'j' is divided by any number in the list and remainder is 0, then the number is not a prime number, which means I can break the loop
break
else:
prime_list.append(i) # Append the prime number to the list
return str(prime_list)[1:-1] # Returns '[2,3,5,7..]', I use the square brackets the get rid of the brackets themselves
print(printPrimeNumbersTo(7)) # >>> 2, 3, 5, 7
The one line I don't understand is marked with an arrow, it's the 8th line of the code.
Why am I dividing the number by 2? And then making it an integer? When I do the calculations, it works, but... where is the logic? Anybody help?
The biggest number which could possibly be an even factor of a number is the half of that number. The integer division operator // produces this number as an integer.
Because of how range works, the ending index needs to be the desired number plus one.
There are two points to note:
the code needs to be indented correctly, in Python indentation matters as it forms the code blocks.
aside from this and specifically adressing the question: the range function that you refer to requires integers otherwise it would throw an typeerror like this: 'float' object cannot be interpreted as an integer .
# this will throw an error
for i in range(1, 10.5):
print(i)
# this will work
for i in range(1, 10):
print(i)
So the reason why the line of code you queried was written like that was to ensure that the upper bound of the range was an integer.
You should also note that the // has a meaning, for example try this:
x = 5//2
print(x)
y = 5/2
print(y)
x is the integer part only (x=2)
y is the full number (y=2.5)
In terms of implementaiton, there are a number of methods that would be better (suggested here):
Print series of prime numbers in python
Dividing the number by 2 is done to reduce the number of iterations. For example, the number 12 you can divide it without a remainder by 1,2,3,4,6. Notice that there is no number bigger than (6) which is 12 / 2. And this goes on with all of the numbers.
16 ---> 1,2,8 no number bigger than its half (8)

Can I make this recursion work with negative numbers?

I wrote this code and it's alright with positive numbers, but when I tried negative numbers it crashes. Can you give any hints on how to make it work with negative numbers as well? It needs to be recursive, not iterative, and to calculate the sum of the digits of an integer.
def sum_digits(n):
if n != 0:
return (n % 10 + sum_digits(n // 10))
else:
return 0
if __name__=='__main__':
print(sum_digits(123))
Input: 123
Output: 6
On the assumption that the 'sum' of the three digits of a negative number is the same as that of the absolute value of that number, this will work:
def sum_digits(n):
if n < 0:
return sum_digits(-n)
elif n != 0:
return (n % 10 + sum_digits(n // 10))
else:
return 0
That said, your actual problem here is that Python's handling of modulo for a negative number is different than you expect:
>>> -123 % 10
7
Why is that? It's because of the use of trunc() in the division. This page has a good explanation, but the short answer is that when you divide -123 by 10, in order to figure out the remainder, Python truncates in a different direction than you'd expect. (For good, if obscure, reasons.) Thus, in the above, instead of getting the expected 3 you get 7 (which is 10, your modulus, minus 3, the leftover).
Similarly, it's handling of integer division is different:
>>> -123 // 10
-13
>>> 123 // 10
12
This is un-intuitively correct because it is rounding 'down' rather than 'towards zero'. So a -12.3 rounds 'down' to -13.
These reasons are why the easiest solution to your particular problem is to simply take the absolute value prior to doing your actual calculation.
Separate your function into two functions: one, a recursive function that must always be called with a non-negative number, and two, a function that checks its argument can calls the recursive function with an appropriate argument.
def sum_digits(n):
return _recursive_sum_digits(abs(n))
def _recursive_sum_digits(n):
if n != 0:
return (n % 10 + sum_digits(n // 10))
else:
return 0
Since _recursive_sum_digits can assume its argument is non-negative, you can dispense with checking its sign on every recursive call, and guarantee that n // 10 will eventually produce 0.
If you want to just sum the digits that come after the negative sign, remove the sign by taking the absolute value of the number. If you're considering the first digit of the negative number to be a negative digit, then manually add that number in after performing this function on the rest of the digits.
Here is your hint. This is happening because the modulo operator always yields a result with the same sign as its second operand (or zero). Look at these examples:
>>> 13 % 10
3
>>> -13 % 10
7
In your specific case, a solution is to first get the absolute value of the number, and then you can go on with you approach:
def sum_digits(n):
n = abs(n)
if n != 0:
return (n % 10 + sum_digits(n // 10))
else:
return 0

Python Debugging: weird event when negative sign is in front

I was doing an assignment question.
Write a program, divisible_by_11(num), to return the divisibility of num
by 11. i.e. divisible_by_11(num) should return True is num is divisible by 11,
or False otherwise. Implement this function recursively and using the following algorithm.
Note: a number is divisible by 11 if the difference between the sum of odd digits
and the sum of even digits is divisible by 11. Note that 0 is divisible by 11.
def divisible_by_11(num):
def helper(num,i):
if num==0:
return 0
elif i%2:
return helper(num//10,i+1)-num%10
Question is about replacing the above line with return -num%10+ helper(num//10,i+1)
elif i%2==0:
return num%10+helper(num//10,i+1)
return helper(num,0)%11==0
this code works, however if I wrote return -num%10+ helper(num//10,i+1) instead of return helper(num//10,i+1)-num%10, my code would fail. Can anyone tell me what's happening?
The issue with the alternate form is due to order of operations. The unary-minus operator binds more tightly than the mod operator. That is, the expression -num%10 is interpreted as (-num) % 10, and the modulus of a negative number is not the same thing as its last digit.
There are a few ways you could fix it. The easiest would probably be to add your own parentheses so that the mod happens first: return -(num%10) + helper(num//10,i+1) should work as expected.
Unrelated to that issue, I'm very skeptical that your assignment allows you to do %11 in the final return, since that operation is all you would need to solve the whole problem without the rest!
Instead, I suspect it wants you to use recursion for that part too (and maybe not for adding up the digits). Instead of return helper(num,0)%11==0, try:
while num > 10:
num = helper(num, 0)
return num == 0

Debugging IndexError: Trivial sum generation problem

I can't wrap my head around what's causing the index error here, not exactly looking for a quick fix. Let me know however if my code repulses you/is incredibly ineffectual. The goal is to generate palindromes produced by the product of two four digit numbers.
Code:
for x in range(10000):
for y in range(10000):
product = str(x*y)
lengthprod = len(str(product))
for digit in range(lengthprod+1):
if (product[digit]==product[lengthprod-digit]):
print x,"x",y,"=",product
Traceback:
Traceback (most recent call last):
File "<pyshell#31>", line 6, in <module>
if (product[digit]==product[lengthprod-digit]):
IndexError: string index out of range
Converting a number to a string is generally a slow operation, since there are many possibilities in general (integers, floating point, scientific notation, maybe something exotic like fractions or imaginary numbers, not to mention things like handling leading zero or overwidth numbers or rounding to two decimal places). Thus, it is often a better approach for checking if a positive integer is a palindrome to reverse the digits numerically by repeatedly taking the input modulo 10 to extract the last digit, adding the digit to an accumulator that is multiplied by 10 at each step, then dividing the input number by 10 before looping. I don't speak Python, so here is my Scheme program to reverse a number:
(define (rev n)
(let loop ((n n) (r 0))
(if (zero? n) r
(loop (quotient n 10)
(+ (* r 10) (modulo n 10))))))
Then you can check if the number is a palindrome by checking if the input number equals its reversal.
Edit: Here it is in Python:
def rev(n):
r = 0
while n > 0:
r = r * 10 + n % 10
n = n // 10
return r
You iterate over values 0...lengthprod , but the legal subscripts for product are 0...lengthprod-1.
The last index is out of bounds. It references an element that is one byte beyond the end of the string.
Two changes:
1: range(0, lengthprod+1) should be range(0, lengthprod)
See documentation on range()
2: product[lengthprod-digit] should be product[lengthprod-digit-1]
Off by one error since lengthprod is a length (1 based) and digit is an index (0 based).
Note, this will only give you valid "single digit" palindromes, but gets you past the index out of range error.
Your code repulses me!
(Sorry, I wouldn't normally be so rude, but since you asked for it... ;)
Use xrange rather than range for long loops like this.
Start the range from 1 rather than 0 unless you don't mind all the duplicated trivial results.
Since multiplication commutes, you might want to loop over a "triangle" rather than a "square" to avoid duplicates.
Your variable name product shadows a function from numeric core.
The question says you're interested in the "product of two four digit numbers", but your code has no such restrictions on the number of digits in the numbers. If you want the four digit numbers as input, just start your xrange(start, stop) from 1000.
Since your stated "goal is to generate palindromes", how about to try it with the correct tool for the job: generators!
def pairs(n):
for x in xrange(n):
for y in xrange(n):
yield (x,y)
pairs_generator = pairs(100)
filter(None, ['{x}*{y}={xy}'.format(x=x,y=y,xy=x*y) if str(x*y) == str(x*y)[::-1] else None for x,y in pairs_generator])
I kept my generator simple for clarity's purpose. I will leave it as an exercise for you to simply make a generator to spit out the palindromes. This will involve moving the logic which I have put in my list comprehension into the generator (or you could make a new palindrome_generator which uses a pairs_generator).
Have fun!

Categories