How to add numbers in a string - python

Im new to python and i have a homework to validate a credit card number. I finished the first two conditions but Im stucked with #3 and #4 conditions. Any help is appreciated
Conditions:
The first digit must be a 4.- done
The fourth digit must be one greater than the fifth digit; keep in mind that these are separated by a dash since the format is ####-####-####.-done
The sum of all digits must be evenly divisible by 4.-need help
If you treat the first two digits as a two-digit number, and the seventh and eighth digits
as a two-digit number, their sum must be 100.- need help
def verify(number) : # do not change this line!
# write your code here so that it verifies the card number
#condtion 1
if number[0] != '4':
return "violates rule #1"
#condition 2
if int(number[3]) != (int(number[5]) + 1) :
return "violates rule #2"
#condition 3
for i in number:
if i >= '0' and i !='-':
# be sure to indent your code!
return True # modify this line as needed
input = "4037-6000-0000" # change this as you test your function
output = verify(input) # invoke the method using a test input
print(output) # prints the output of the function
# do not remove this line!
Expected outputs:
● "5000-0000-0000": violates rule #1
● "4000-0000-0000": passes rule #1, violates rule #2
● "4007-6000-0000": passes rules #1-2, violates rule #3
● "4037-6000-0000": passes rules #1-3, violates rule #4
● “4094-3460-2754”: passes all rules

For condition #3
Strings in Python are iterable meaning you can pass over them in a for loop. Each element in the loop is a character in the string. So if you did
for char in "4094-3460-2754":
print(char)
You'd get:
4
0
9
4
-
3
4
etc.
Using this, you can calculate the sum of every number in the input and check if it's divisible by 4. Two things to note, you need to convert the characters to integers first (using int). You can't do
"4" + "0"
But you can do
int("4") + int("0")
You'll need to exclude "-" from your sum as well using if.
Second, we check if two numbers are divisible in Python using modulo (%). The result is the remainder, and if the remainder is 0 then the first argument is divisible by the second.
16 % 4 == 0 # divisible by 4
21 % 4 == 1 # not divisible by 4
For condition #4
In addition to being iterable, strings in Python can be accessed by their index (starting at 0)
"4094-3460-2754"[0] == "4"
"4094-3460-2754"[1] == "0"
"4094-3460-2754"[2] == "9"
"4094-3460-2754"[0:1] == "40"
"4094-3460-2754"[1:2] == "09"
So you can access multiple characters and treat them as an integer:
int("4094-3460-2754"[0:1]) == 40
Now you can add them together and see if they equal 100.

For rule 3, you need to sum all the numbers and the check if the remainder on division by 4 is zero:
#condition 3
s = 0
for i in number:
if i != '-':
s += int(i)
if s % 4 != 0:
return "violates rule #3"
For rule 4 you can get the sum of int of substrings:
if (int(number[0:2]) + int(number[7:8])) != 100:
return "violates rule #4"
Full code :
def verify(number) : # do not change this line!
# write your code here so that it verifies the card number
#condtion 1
if number[0] != '4':
return "violates rule #1"
#condition 2
if int(number[3]) != (int(number[5]) + 1) :
return "violates rule #2"
#condition 3
s = 0
for i in number:
if i != '-':
s += int(i)
if s % 4 != 0:
return "violates rule #3"
if (int(number[0:2]) + int(number[7:9])) != 100:
return "violates rule #4"
# be sure to indent your code!
return True # modify this line as needed
input = "4037-6000-0000" # change this as you test your function
output = verify(input) # invoke the method using a test input
print(output) # prints the output of the function
# do not remove this line!

I prefer removing the dashes - from the number first so that it can be easy to work with. You can also do it without removing it like you tried.
# split it into parts separated by dashes
# consider 4094-3460-2754
no_dashes = number.split('-')
print(no_dashes) # ['4094', '3460', '2754']
# combine the numbers without dashes
no_dashes = ''.join(no_dashes)
print(no_dashes) # 409434602754
# convert it into a list of integers so that it is more easier to work with
number = [int(x) for x in no_dashes]
print(number) # [4, 0, 9, 4, 3, 4, 6, 0, 2, 7, 5, 4]
You can read about split() and join() here.
Now, as you mentioned, the first condition is simple and you can simply check if the first number is 4 or not.
# 1st condition
if number[0] != 4:
return 'Violates #1'
The second condition is also simple:
# 2nd condition
# 4th digit is a[3] and 5th digit is a[4]
if number[3] != number[4] + 1:
return 'Viloates #2'
For the third condition, you just have to find the sum of every digit in the number. Since, we already converted the number into an integer array, this is also easy using the sum() function:
# 3rd condition
# Find the sum
num_sum = sum(number)
print(num_sum) # 48
# now check if the sum is divisible by 4
if num_sum % 4 != 0:
return 'Violates #3'
Now, for the fourth condition, you need to treat the 1st & 2nd digit as a two-digit number and same with the 7th and 8th digit. You can convert it into two-digit number as follows:
# 1st digit is number[0]
# 2nd digit is number[1]
# 7th digit is number[6]
# 8ty digit is number [7]
# convert 1st two digits into a two-digit number
x = number[0] * 10 + number[1]
# convert 7th and 8th digits into a two-digit number
y = number[6] * 10 + number[7]
Now you can check if their sum is 100 or not:
if x + y != 100:
return 'Violates #4'
So, the combined program becomes (with some steps merged):
def verify(number):
number = [int(x) for x in ''.join(number.split('-'))]
if number[0] != 4:
return 'Violates #1'
if number[3] != number[4] + 1:
return 'Viloates #2'
if sum(number) % 4 != 0:
return 'Violates #3'
if (number[0] * 10 + number[1] + number[6] * 10 + number[7]) != 100:
return 'Violates #4'
return True
But the above program will only give the 1st condition that fails. You can modify it further if you want as follows:
def verify(number):
failed = []
number = [int(x) for x in ''.join(number.split('-'))]
if number[0] != 4:
failed += [1]
if number[3] != number[4] + 1:
failed += [2]
if sum(number) % 4 != 0:
failed += [3]
if (number[0] * 10 + number[1] + number[6] * 10 + number[7]) != 100:
failed += [4]
res = 'Violates ' + (', '.join[str(x) for x in failed])
return res if len(failed) != 0 else 'Passed'
print(verify('4094-3460-2754')) # Passed
print(verify('4037-6000-0000')) # Violates 4
You can again modify it to display passed conditions too. I leave it upto you!

The sum of all digits must be evenly divisible by 4.
You can check this with a conditional statement like:
if sum_of_nums % 4 != 0:
print("Violates rule 3!")
This checks if there is any remainder when dividing by four, and if there is no remainder it will divide evenly and the expression will equal zero. If it does not divide evenly it will not equal 0!
If you treat the first two digits as a two-digit number, and the seventh and eighth digits as a two-digit number, their sum must be 100.
Here you can reference the characters of a string like you do a list. If the input is always going to be consistent you can hard code the references, change them to ints and then add them together and check them with a conditional statement
first_num = input[0]+input[1]
first_num = int(first_num) #now an int
second_num = input[6]+input[7]
second_num = int(second_num)
if first_num + second_num != 100:
print("Violates rule 4!")

Related

calculating the last non-zero digit of a factorial- why does my code pass some tests but fail others?

I am writing code to solve the following codewars question: https://www.codewars.com/kata/5f79b90c5acfd3003364a337/train/python
My idea is to take all the integers from 1 to n, and take the last digit of each of these integers (bar 0), multiply them together, and return the 'last' non-zero digit of the result:
def last_digit(n):
factorials = []
factorials_n = 1
for i in range(1,n + 1):
i = str(i)
i = i[::-1]
for j in i:
if j == "0":
break
factorials.append(j)
break
# at this point factorials contains the first non-zero integers of each integer in reverse
for i in factorials:
factorials_n = factorials_n * int(i)
factorials_n = str(factorials_n)
factorials_n = factorials_n[::-1]
for i in factorials_n:
if i != "0":
return int(i)
The code passes a number of tests, but fails for 387 (returns 6, should be 2) and 1673 (returns 2 should be 4). I've tried doing print statements as debug but the code seems fine, perhaps it's the logic that fails at some point- any ideas?
The problem here is with the logic. Since you are dropping all the cases where the number ends in 0, we do not arrive at the correct answer.
Consider 2 x 8 x 30. To get the last digit of the factorial, multiplying last digits would suffice, but to find the last non zero digit, you have to evaluate 2 x 8 x 3
instead.
Using this solution as a reference, here's what you can do:
def last_digit(n):
# factorials = []
# factorials_n = 1
last = 1
d2 = 0
for i in range(1,n + 1):
ii = i
print(ii)
while(ii%2==0):
d2 +=1
ii = ii/2
while(ii%5==0):
d2 -=1
ii = ii/5
print(d2)
last = (last * ii)%10
print(last)
for i in range(0,d2):
last = (last *2)%10
return int(last)
Your code passes the test cases for numbers uptill 24, it fails when the non-zero digit from 25! gives an incorrect answer which get propogated forward for the numbers after it.
And also we can simply use the modulo operator to get the very last digit instead of converting it into a string
Example: 1234 % 10 equals 4 (which is the last digit)
My solution:
def last_digit(n):
factorial = 1
for i in range(1, n + 1):
# compute the factorial
prod = factorial * i
# keep dividing the product by 10 until the last digit is a !0 digit
while prod % 10 == 0:
prod = prod // 10
# only store the last 3 digits of the computed product.
# You can keep more digits to get accurate results for
# when the numbers are higher than 10000
factorial = prod % 1000
# return the last digit
return factorial % 10
As i said earlier, when the last !0 digit from 24! (6) is multiplied with 25, it outputs 150 which after removing the 0 gives 5 but it instead should be 4. Hence, in order to solve this we keep at least the last 3 digits instead of only the last digit.
Example: 6 * 25 = 150 => 5 (last !0 digit)
936 * 25 = 23400 => 4 (last !0 digit)
PS: !0 = non-zero

Check if a number can be formed by sum of a number and its reverse

I want to check if a given number can be formed by another number say b and reverse(b). For example 12 == 6+6, 22 == 11 + 11 and 121 == 29+92. One thing I have figured out is if the number is multiple of 11 or it is an even number less than 20, then it can be formed. I tried to implement this below:
num = 121
if num%11==0:
print('Yes')
else:
if num%2==0 and num<20:
print('Yes')
else:
for j in range(11,(int(num)//2)+1):
if j+int(str(j)[::-1])==num:
print('Yes')
break
However, if the condition goes into the for loop, it gives TLE. Can any other conditions be given?
Update: If the reversed number has trailing zeroes, it should be removed and then added. For example: 101 == 100+1. I am looking for an optimized form of my code. Or I think I am missing some conditions which can take O(1) time, similar to the condition if num%11==0: print('Yes')
All the previous answers are not really a check. It's more a brute force try and error.
So let's do it a little bit smarter.
We start with a number, for example 246808642. we can reduce the problem to the outer 2 place values at the end and start of the number. Let us call this values A and B at the front and Y and Z on the back. the rest, in the middle, is Π. So our number looks now ABΠYZ with A = 2, B = 4, Π = 68086, Y = 4 and Z = 2. (one possible pair of numbers to sum up for this is 123404321). Is A equal to 1, this is only possible for a sum greater 10 (An assumption, but i guess it works, some proof would be nice!).
so if it is a one, we know that the second last number is one greater by the carry over. So we ignore A for the moment and compare B to Z, because they should be the same because both are the result of the addition of the same two numbers. if so, we take the remaining part Π and reduce Y by one (the carry over from the outer addition), and can start again at the top of this chart with Π(Y-1). Only a carry over can make B one bigger than Z, if it's so, we can replace B by one and start with 1Π(Y-1) at the top. B-1!=Z and B!=Z, we can stop, this isnt possible for such a number which is the sum of a number and its reversed.
If A != 1, we do everything similiar as before but now we use A instead of B. (I cut this here. The answer is long enough.)
The code:
import time
def timing(f):
def wrap(*args, **kwargs):
time1 = time.time()
ret = f(*args, **kwargs)
time2 = time.time()
print('{:s} function took {:.3f} ms'.format(f.__name__, (time2-time1)*1000.0))
return ret
return wrap
#timing
def check(num):
num = str(num)
if (int(num) < 20 and int(num)%2 == 0) or (len(num) ==2 and int(num)%11 == 0):
return print('yes')
if len(num) <= 2 and int(num)%2 != 0:
return print('no')
# get the important place values of the number x
A = num[0]
B = num[1]
remaining = num[2:-2]
Y = num[-2]
Z = num[-1]
# check if A = 1
if A == '1':
# A = 1
# check if B == Z
if B == Z:
# so the outest addition matches perfectly and no carry over from inner place values is involved
# reduce the last digit about one and check again.
check(remaining + (str(int(Y)-1) if Y != '0' else '9'))
elif int(B)-1 == int(Z):
# so the outest addition matches needs a carry over from inner place values to match, so we add to
# to the remaining part of the number a leading one
# we modify the last digit of the remaining place values, because the outest had a carry over
check('1' + remaining + (str(int(Y)-1) if Y != '0' else '9'))
else:
print("Not able to formed by a sum of a number and its reversed.")
else:
# A != 1
# check if A == Z
if A == Z:
# so the outest addition matches perfectly and no carry over from inner place values is involved
check(B + remaining + Y)
elif int(A) - 1 == int(Z):
# so the outest addition matches needs a carry over from inner place values to match, so we add to
# to the remaining part of the number a leading one
# we modify the last digit of the remaining place values, because the outest had a carry over
check('1' + B + remaining + Y)
else:
print("Not able to formed by a sum of a number and its reversed.")
#timing
def loop_check(x):
for i in range(x + 1):
if i == int(str(x - i)[::-1]) and not str(x - i).endswith("0"):
print('yes, by brute force')
break
loop_check(246808642)
check(246808642)
Result:
yes, by brute force
loop_check function took 29209.069 ms
Yes
check function took 0.000 ms
And another time we see the power of math. Hope this work for you!
You can brute force it like this:
def reverse_digits(n):
return int(str(n)[::-1])
def sum_of_reversed_numbers(num):
for i in range(num + 1):
if i == reverse_digits(num - i):
return i, num - i
return None
print("Yes" if sum_of_reversed_numbers(num) else "No")
Can you provide the constraints of the problem?
Here is something you can try:
i = 0
j = num
poss = 0
while(i<=j):
if(str(i)==str(j)[::-1]):
poss = 1
break
i+=1
j-=1
if(poss):
print("Yes")
else:
print("No")
You can do it without str slicing:
def reverse(n):
r = 0
while n != 0:
r = r*10 + int(n%10)
n = int(n/10)
return r
def f(n):
for i in range(n + 1):
if i + reverse(i) == n:
return True
return False
print('Yes' if f(101) else 'No')
#Yes
The basic idea of my solution is that you first generate a mapping of digits to the digits that could make them up, so 0 can be made by either 0+0 or 1+9, 2+8 etc. (but in that case there's a carried 1 you have to keep in mind on the next step). Then you start at the smallest digit, and use that code to check each possible way to form the first digit (this gives you candidates for the first and last digit of the number that sums with its reverse to give you the input number). Then you move on the second digit and try those. This code could be greatly improved by checking both the last and the first digit together, but it's complicated by the carried 1.
import math
candidates = {}
for a in range(10):
for b in range(10):
# a, b, carry
candidates.setdefault((a + b) % 10, []).append((a, b, (a + b) // 10))
def sum_of_reversed_numbers(num):
# We reverse the digits because Arabic numerals come from Arabic, which is
# written right-to-left, whereas English text and arrays are written left-to-right
digits = [int(d) for d in str(num)[::-1]]
# result, carry, digit_index
test_cases = [([None] * len(digits), 0, 0)]
if len(digits) > 1 and str(num).startswith("1"):
test_cases.append(([None] * (len(digits) - 1), 0, 0))
results = []
while test_cases:
result, carry, digit_index = test_cases.pop(0)
if None in result:
# % 10 because if the current digit is a 0 but we have a carry from
# the previous digit, it means that the result and its reverse need
# to actually sum to 9 here so that the +1 carry turns it into a 0
cur_digit = (digits[digit_index] - carry) % 10
for a, b, new_carry in candidates[cur_digit]:
new_result = result[::]
new_result[digit_index] = a
new_result[-(digit_index + 1)] = b
test_cases.append((new_result, new_carry, digit_index + 1))
else:
if result[-1] == 0 and num != 0: # forbid 050 + 050 == 100
continue
i = "".join(str(x) for x in result)
i, j = int(i), int(i[::-1])
if i + j == num:
results.append((min(i, j), max(i, j)))
return results if results else None
We can check the above code by pre-calculating the sums of all numbers from 0 to 10ⁿ and their reverse and storing them in a dict of lists called correct (a list because there's many ways to form the same number, eg. 11+11 == 02 + 20), which means we have the correct answers for 10ⁿ⁻¹ we can use to check the above function. Btw, if you're doing this a lot with small numbers, this pre-calculating approach is faster at the expense of memory.
If this code prints nothing it means it works (or your terminal is broken :) )
correct = {}
for num in range(1000000):
backwards = int(str(num)[::-1])
components = min(num, backwards), max(num, backwards)
summed = num + backwards
correct.setdefault(summed, []).append(components)
for i in range(100000):
try:
test = sum_of_reversed_numbers(i)
except Exception as e:
raise Exception(i) from e
if test is None:
if i in correct:
print(i, test, correct.get(i))
elif sorted(test) != sorted(correct[i]):
print(i, test, correct.get(i))
Stole the idea from #Doluk. I was asked this question in a test today. I couldn't solve it then. With Doluk's idea and thinking seriously on it below is a decision tree kind for one level of recursion. I might be wrong as I haven't ran this algorithm.
Let n be the number, we want to check if special
case 1: leading number is not 1
case 1a: no carry over from inner addition
abcdefgh
hgfedcba
x x => (a+h) < 10
if both ends are same in n, strip both sides by one digit and recurse
case 1b: carry over from inner addition
1
abcdefgh
hgfedcba
(x+1)......(x) => (a+h+1) < 10
if left end is 1 greater than right end in n, strip both sides by one digit, add digit 1 on the left and recurse
case 2: leading number is 1
case 2a: no carry over from inner addition
1 1
abcdefgh
hgfedcba
1x x => (a+h) >= 10
strip - if second and last digit are same, strip two digits from left and one from right, from the remaining number minus 1 and recurse.
case 2b: carry over from inner addition
case 2bi: a+h = 9
11
abcdefgh
hgfedcba
10......9
strip - two from left and one from right and recurse.
case 2bj: a+h >= 10
11 1
abcdefgh
hgfedcba
1(x+1)......x
strip - two from left and one from right and subtract 1 from number and recurse.
In my question, they gave me an array of numbers and they asked me to find numbers which of them are special (Which can be formed by the sum and reverse of that number).
My brute force solution was to iterate from 0 to 1000000 and insert them into the set and last check for each element in the set.
Time Complexity: O(n)
Space Complexity: O(n)
where n is the highest number allowed.

Validate Credit Card Number Using Luhn Algorithm Python

I am trying to implement Luhn algorithm in Python. Here is my code
def validate(n):
if len(str(n)) > 16:
return False
else:
if len(str(n)) % 2 == 0:
for i in str(n[0::2]):
digit = int(str(n[i])) * 2
while digit > 9:
digit = sum(map(int, str(digit)))
dig_sum = sum(map(int, str(n)))
return True if dig_sum % 10 == 0 else False
elif len(str(n)) % 2 != 0:
for i in str(n[1::2]):
digit = int(str(n[i])) * 2
while digit > 9:
digit = sum(map(int, str(digit)))
dig_sum = sum(map(int, str(n)))
return True if dig_sum % 10 == 0 else False
I keep getting the error
TypeError: 'int' object has no attribute '__getitem__
Following is python implementation of Lunh Algorith to detect a valid credit card number. Function takes a number as string and return whether its valid credit card or not.
Its based on the steps mentioned in the following link: https://www.codeproject.com/Tips/515367/Validate-credit-card-number-with-Mod-algorithm
Step 1 - Starting with the check digit double the value of every other digit (right to left every 2nd digit)  
Step 2 - If doubling of a number results in a two digits number, add up the digits to get a single digit number. This will results in eight single digit numbers.
Step 3 - Now add the un-doubled digits to the odd places
Step 4 - Add up all the digits in this number
If the final sum is divisible by 10, then the credit card number is valid. If it is not divisible by 10, the number is invalid. 
def luhn(ccn):
c = [int(x) for x in ccn[::-2]]
u2 = [(2*int(y))//10+(2*int(y))%10 for y in ccn[-2::-2]]
return sum(c+u2)%10 == 0
#Test
print(luhn("49927398716"))
It is hard to tell without the complete error message, but it is likely because you confused in some places where you put the indexing and where you put the string conversion, for example: for i in str(**n[1::2]**) and digit = int(str(**n[i]**)) * 2
A good way to handle it is to just create a temporary variable n_str = str(n), and use it instead of str(n) over and over again.

Taking away from nearest 10

Okay, i have made my code so that a user can input 7 numbers and times them by 1 for the odd index numbers and 3 for the even:
num = str(input("Please enter 7 numbers")
length = len(num)
while length < 7 or length ? 7:
num = input("Only enter 7 numbers")
string = ''
for t in range(1,8):
if t % 2 == 0:
string += str(t * 3)
else:
string += str(t) + ' '
print(string)
This works fine, but now i need to add all the numbers up and take it away from the highest 10 so for example, all the numbers add up to 53 i need to take that away from 60 which leaves me 7, that will be my eight number, then after i have got that number i print it out, how do i get it to add the numbers up and the take it away from the highest 10 and output the difference of the two into the numbers i already have?
Thanks
Brad
If you have a number, x, which is equal to 53, then going up should be math.ceil(x) except that math.ceil() rounds for 1. To account for that, we divide by 10, use math.ceil(), and then multiply by 10 again:
import math
rounded_up = math.ceil(x / 10) * 10
result = rounded_up - x
Brad could you clarify your question? Also your above code does not work.
Missing a bracket on the first line and this isn't valid while length < 7 or length ? 7:
I believe this is what you're looking for:
def take_away_from_nearest(number, nearest):
return nearest - (number % nearest)
Usage:
>>> take_away_from_nearest(53, 10)
7
edit:
If I understand you correctly, this would be the entire code:
while True:
# this is just an easy way to keep asking until the input is correct
num = input("Please enter 7 numbers: ")
if len(num) == 7:
break
weird_sum = 0 #here's where we're gonna sum up the numbers; the "eighth number"
for index, character in enumerate(num):
if index % 2 == 0: # index is odd, so count the character thrice
print(3 * int(character))
weird_sum += 3 * int(character)
else: # index is even
print(int(character))
weird_sum += int(character)
print(10 - (weird_sum % 10)) # 10 minus (weird_sum modulo 10)
# and finally, adding them all up and checking whether it ends with 0:
print((10-(weird_sum % 10) + weird_sum) % 10 == 0) # prints True

Luhn checksum method; separating two digits and finding the sum of that list

I am currently trying to use the luhn method to determine whether a credit card is valid or not in python and here is what I have so far:
print('What is your Credit Card number? :) (please put a space between each number)')
a = [int(x) for x in input().split()]
lengthy = len(a)
print(lengthy)
a.reverse()
print(a)
listx2 = []
listx1 = []
for x in range(len(a)):
modulus = x % 2
print(x, a[x])
if modulus != 0:
listx2.append(a[x]*2)
else:
listx1.append(a[x])
print(listx2)
print(listx1)
I don't know how to do the next step which is getting the sum of all of the digits of the numbers multiplied by two.(listx2) I have looked at different programs with the luhn method but I just can't seem to pick that part out. Thanks!
This is my interpretation of the Luhn algo.
def luhn(sequence):
digits = [int(digit) for digit in str(sequence)] # converts a full string of nums to a list comp of individual numbers
odd = digits[-1::-2] # string stepping (-1) indicates last item in list (-2) means to travel back another 2
even = digits[-2::-2]
checksum = 0
checksum += sum(odd)
evenmod = []
for digit in even:
if digit * 2 > 9:
digit = digit * 2
digit = int(str(digit)[0]) + int(str(digit)[1])
else:digit = digit * 2
evenmod.append(digit)
checksum += sum(evenmod)
if checksum % 10 == 0:
return True
else:
return False
print luhn(378282246310005)
print luhn(111111111111111)
print luhn(4751290083628479)
print luhn(5573485043994670)
Separate the even and the odd indeces to separate lists, then use a for statement to loop through the list, multiplying the list entries by two.
Notice the if statement that catches the issue with (e.g) 8 * 2 = 16.
Use sum:
summed_x2 = sum(listx2)

Categories

Resources