def check(barcode):
if not len(barcode) == 13:
return False
digits = list(map(int, barcode))
# 1. Add the values of the digits in the
# even-numbered positions: 2, 4, 6, etc.
even_sum = digits[1] + digits[3] + digits[5] + digits[7] + digits[9] + digits[11]
# 2. Multiply this result by 3.
even_sum_three = even_sum * 3
# 3. Add the values of the digits in the
# odd-numbered positions: 1, 3, 5, etc.
odd_sum = digits[0] + digits[2] + digits[4] + digits[6] + digits[8] + digits[10]
# 4. Sum the results of steps 2 and 3.
total_sum = even_sum_three + odd_sum
# 5. The check character is the smallest number which,
# when added to the result in step 4, produces a multiple of 10.
next_ten = (math.ceil(total_sum / 10)) * 10
check_digit = next_ten - total_sum
# 6. if the check digit and the last digit of the
# barcode are OK return true;
if check_digit == digits[12]:
return True
else:
return False
I have the above code. It calculates the checksum of an ean number. I tried to speed it by using Cython. This code gets used in a loop. The variable barcode is a string.
But I failed to improve the speed. I tried:
np.array(list(map(int, barcode))) - That made it slightly slower
np.ceil() instead of math.ceil() - Also made it slightly slower
cdef bool def check(.... - Also did not help
What else could I do?
You could start by optimizing your function itself. Having a look at
# 5. The check character is the smallest number which,
# when added to the result in step 4, produces a multiple of 10.
next_ten = (math.ceil(total_sum / 10)) * 10
check_digit = next_ten - total_sum
you could also do something like next_ten = 10 - total_sum % 10 to get the check character. There you got rid of the math.ceil. As extra, this code also works in Python 2. So at the end, collapsing all your code, you could end up with just doing
def check(barcode):
if not len(barcode) == 13:
return False
return not (3*sum(map(int,barcode[1::2]))+sum(map(int,barcode[::2])))%10
Of course you could also use list comprehension or itertools, but in my testing there was not much difference to account for. But the "most" efficient way to do it, was not to use any fancy python programming technique at all:
def check(bc):
if not len(bc) == 13:
return False
return not (3*(int(bc[1])+int(bc[3])+int(bc[5])+int(bc[7])+int(bc[9])+int(bc[11]))+int(bc[0])+int(bc[2])+int(bc[4])+int(bc[6])+int(bc[8])+int(bc[10])+int(bc[12]))%10
A note at the end: With all my tests, Python 2 was faster.
Related
I want to draw a triangle of asterisks from a given n which is an odd number and at least equal to 3. So far I did the following:
def main():
num = 5
for i in range(num):
if i == 0:
print('-' * num + '*' * (i + 1) + '-' * num)
elif i % 2 == 0:
print('-' * (num-i+1) + '*' * (i + 1) + '-' * (num-i+1))
else:
continue
if __name__ == "__main__":
main()
And got this as the result:
-----*-----
----***----
--*****--
But how do I edit the code so the number of hyphens corresponds to the desirable result:
-----*-----
----***----
---*****---
--*-----*--
-***---***-
*****-*****
There's probably a better way but this seems to work:
def triangle(n):
assert n % 2 != 0 # make sure n is an odd number
hyphens = n
output = []
for stars in range(1, n+1, 2):
h = '-'*hyphens
s = '*'*stars
output.append(h + s + h)
hyphens -= 1
pad = n // 2
mid = n
for stars in range(1, n+1, 2):
fix = '-'*pad
mh = '-'*mid
s = '*'*stars
output.append(fix + s + mh + s + fix)
pad -= 1
mid -= 2
print(*output, sep='\n')
triangle(5)
Output:
-----*-----
----***----
---*****---
--*-----*--
-***---***-
*****-*****
Think about what it is you're iterating over and what you're doing with your loop. Currently you're iterating up to the maximum number of hyphens you want, and you seem to be treating this as the number of asterisks to print, but if you look at the edge of your triforce, the number of hyphens is decreasing by 1 each line, from 5 to 0. To me, this would imply you need to print num-i hyphens each iteration, iterating over line number rather than the max number of hyphens/asterisks (these are close in value, but the distinction is important).
I'd recommend trying to make one large solid triangle first, i.e.
-----*-----
----***----
---*****---
--*******--
-*********-
***********
since this is a simpler problem to solve and is just one modification away from what you're trying to do (this is where the distinction between number of asterisks and line number will be important, as your pattern changes dependent on what line you're on).
I'll help get you started; for any odd n, the number of lines you need to print is going to be (n+1). If you modify your range to be over this value, you should be able to figure out how many hyphens and asterisks to print on each line to make a large triangle, and then you can just modify it to cut out the centre.
I'm working through the Codility problems and I have gotten the first one almost correct. The task is to write a function which returns the longest binary gap (a sequence of 0s in between 1s) in a binary number. I have gotten all of the test numbers correct apart from 9, which should be 2 (its binary representation is 1001) but which my function returns as 0. I can't seem to figure out why.
My function is as follows:
def Solution(N):
x = bin(N)[2:]
x_string = str(x)
y = (len(x_string))
count = 0
max = 0
for index, item in enumerate(x_string):
if item == "1":
count = 0
elif item == "0" and x_string[index + 1:y-1] != "0"*(y -1 - (index + 1)):
count = count + 1
if count > max:
max = count
print(max)
The complicated indexing and second condition in the elif statement is so that when a 0 is not contained between two 1s then it isn't recognised as the beginning of a binary gap e.g. when the for loop looks at the second character in bin(16) = 10000, it doesn't set count to 1 because all of the remaining characters in the string are also zero.
Simple solution
x_string[index + 1:y-1] != "0"
this bit wants to take a look at the whole string that's left, but the end argument isn't inclusive,it's exluded, so if string length = 4; string[0:4] is the whole string.
source: https://docs.python.org/3/tutorial/introduction.html
-Sam
I'm trying to solve this problem but it fails with input "226".
Problem:
A message containing letters from A-Z is being encoded to numbers using the following mapping:
'A' -> 1
'B' -> 2
...
'Z' -> 26
Given a non-empty string containing only digits, determine the total number of ways to decode it.
My Code:
class Solution:
def numDecodings(self, s: str) -> int:
decode =[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26]
ways = []
for d in decode:
for i in s:
if str(d) == s or str(d) in s:
ways.append(d)
if int(i) in decode:
ways.append(str(i))
return len(ways)
My code returns 2. It only takes care of combinations (22,6) and (2,26).
It should be returning 3, so I'm not sure how to take care of the (2,2,6) combination.
Looks like this problem can be broken down into many subproblems thus can be solved recursively
Subproblem 1 = when the last digit of the string is valid ( i.e. non zero number ) for that you can just recur for (n-1) digits left
if s[n-1] > "0":
count = number_of_decodings(s,n-1)
Subproblem 2 = when last 2 digits form a valid number ( less then 27 ) for that you can just recur for remaining (n-2) digits
if (s[n - 2] == '1' or (s[n - 2] == '2' and s[n - 1] < '7') ) :
count += number_of_decodings(s, n - 2)
Base Case = length of the string is 0 or 1
if n == 0 or n == 1 :
return 1
EDIT: A quick searching on internet , I found another ( more interesting ) method to solve this particular problem which uses dynamic programming to solve this problem
# A Dynamic Programming based function
# to count decodings
def countDecodingDP(digits, n):
count = [0] * (n + 1); # A table to store
# results of subproblems
count[0] = 1;
count[1] = 1;
for i in range(2, n + 1):
count[i] = 0;
# If the last digit is not 0, then last
# digit must add to the number of words
if (digits[i - 1] > '0'):
count[i] = count[i - 1];
# If second last digit is smaller than 2
# and last digit is smaller than 7, then
# last two digits form a valid character
if (digits[i - 2] == '1' or
(digits[i - 2] == '2' and
digits[i - 1] < '7') ):
count[i] += count[i - 2];
return count[n];
the above solution solves the problem in complexity of O(n) and uses the similar method as that of fibonacci number problem
source: https://www.geeksforgeeks.org/count-possible-decodings-given-digit-sequence/
This seemed like a natural for recursion. Since I was bored, and the first answer didn't use recursion and didn't return the actual decodings, I thought there was room for improvement. For what it's worth...
def encodings(str, prefix = ''):
encs = []
if len(str) > 0:
es = encodings(str[1:], (prefix + ',' if prefix else '') + str[0])
encs.extend(es)
if len(str) > 1 and int(str[0:2]) <= 26:
es = encodings(str[2:], (prefix + ',' if prefix else '') + str[0:2])
encs.extend(es)
return encs if len(str) else [prefix]
This returns a list of the possible decodings. To get the count, you just take the length of the list. Here a sample run:
encs = encodings("123")
print("{} {}".format(len(encs), encs))
with result:
3 ['1,2,3', '1,23', '12,3']
Another sample run:
encs = encodings("123123")
print("{} {}".format(len(encs), encs))
with result:
9 ['1,2,3,1,2,3', '1,2,3,1,23', '1,2,3,12,3', '1,23,1,2,3', '1,23,1,23', '1,23,12,3', '12,3,1,2,3', '12,3,1,23', '12,3,12,3']
Here is the function i defined:
def count_longest(field, data):
l = len(field)
count = 0
final = 0
n = len(data)
for i in range(n):
count = 0
if data[i:i + l] is field:
while data[i - l: i] == data[i:i + l]:
count = count + 1
i = i + 1
else:
print("OK")
if final == 0 or count >= final:
final = count
return final
a = input("Enter the field - ")
b = input("Enter the data - ")
print(count_longest(a, b))
It works in some cases and gives incorrect output in most cases. I checked by printing the strings being compared, and even after matching the requirement, the loop results in "OK" which is to be printed when the condition is not true! I don't get it! Taking the simplest example, if i enter 'as', when prompted for field, and 'asdf', when prompted for data, i should get count = 1, as the longest iteration of the substring 'as' is once in the string 'asdf'. But i still get final as 0 at the end of the program. I added the else statement just to check the if the condition was being satisfied, but the program printed 'OK', therefore informing that the if condition has not been satisfied. While in the beginning itself, data[0 : 0 + 2] is equal to 'as', 2 being length of the "field".
There are a few things I notice when looking at your code.
First, use == rather than is to test for equality. The is operator checks if the left and right are referring to the very same object, whereas you want to properly compare them.
The following code shows that even numerical results that are equal might not be one and the same Python object:
print(2 ** 31 is 2 ** 30 + 2 ** 30) # <- False
print(2 ** 31 == 2 ** 30 + 2 ** 30) # <- True
(note: the first expression could either be False or True—depending on your Python interpreter).
Second, the while-loop looks rather suspicious. If you know you have found your sequence "as" at position i, you are repeating the while-loop as long as it is the same as in position i-1—which is probably something else, though. So, a better way to do the while-loop might be like so:
while data[i: i + l] == field:
count = count + 1
i = i + l # <- increase by l (length of field) !
Finally, something that might be surprising: changing the variable i inside the while-loop has no effect on the for-loop. That is, in the following example, the output will still be 0, 1, 2, 3, ..., 9, although it looks like it should skip every other element.
for i in range(10):
print(i)
i += 1
It does not effect the outcome of the function, but when debugging you might observe that the function seems to go backward after having found a run and go through parts of it again, resulting in additional "OK"s printed out.
UPDATE: Here is the complete function according to my remarks above:
def count_longest(field, data):
l = len(field)
count = 0
final = 0
n = len(data)
for i in range(n):
count = 0
while data[i: i + l] == field:
count = count + 1
i = i + l
if count >= final:
final = count
return final
Note that I made two additional simplifications. With my changes, you end up with an if and while that share the same condition, i.e:
if data[i:i+1] == field:
while data[i:i+1] == field:
...
In that case, the if is superfluous since it is already included in the condition of while.
Secondly, the condition if final == 0 or count >= final: can be simplified to just if count >= final:.
How do I compute the answer so that the answer is not a hard-coded solution? Like if I wanted to put in another credit card number how can I return the result of that new credit card? Also how can I create one x list rather then the way I have it now with the values split up by 2?
Also here is the original question for reference:
Credit card numbers are validated using Luhn’s formula 3. Implement a program that takes a credit card numbers as a multidimensional array (you may assume it consists of exactly of 16 columns), and returns a list with values Valid if it is a valid card number, and Invalid otherwise.
One way to perform the validity test is as follows:
1. From the rightmost digit, which is the check digit, moving left, double the value of every second digit; if the product of this doubling operation is greater than 9 (e.g., 8 2 = 16), then sum the digits of the products (e.g.,16: 1 + 6 = 7, 18: 1 + 8 = 9).
2. Take the sum of all the digits.
3. If the total is divisible by 10, then the number is valid according to the Luhn formula; else it is not valid.
Note: You can maniplulate card numbers either as strings (using indexing and slicing to extract digits, etc) or as integers (using integer division and remainder to manipulate digits).
My script:
import numpy as py
x = [[7,1],[6,3],[4,5],[6,2],[7,8],[3,4],[6,8],[3,9]] #credit card numbers
x2 = np.array(x)
evryothernum = x2[:,1] #returns every other number / every seconds digit
evryothernum2 = np.multiply(evryothernum,2)
sumdigits = []
def card_validate(x):
evryothernum = x2[:,1] #valid
evryothernum2 = np.multiply(evryothernum,2) #multiplys evryothernum by 2
b=np.sort(evryothernum2, axis = None) #sorts the evryothernum2 array in order
b2 = np.array(b)
b3 = b2[4:8] #shows the highest values aka greater than 9
b3
b3 = [1,7,7,9]
newb3 = np.sum(b3)
newx2 = np.sum(x2[:,0])
total = np.sum(newb3+newx2)
if ( (total % 10) == 0 ):
print "Valid"
else:
print "Invalid"
return card_validate()
Is there an easier way then to do this without Numpy?
The following can be used to implement the logic without using numpy
a=[[4,0,1,2,8,8,8,8,8,8,8,8,1,8,8,1],[4,0,1,2,8,8,8,8,8,8,8,8,1,8,8,2]] #array of credit card numbers
def validate(creditcard_numbers,tmp):
even_index=-1
for j in range(0,16):
sum_val=0
if even_index%2 ==0: #index calculation for even indices
val=creditcard_numbers[even_index]*2
if val>9: # add the digits if the value got after multiplying by 2 is two digit number
while val !=0:
rem=val%10
val=val/10
sum_val=sum_val+rem
tmp[even_index]=sum_val #append the temporary list with the new values which is got by adding the digits if the result of multiplying by 2 is a 2 digit number
else:
tmp[even_index]=val
else:
tmp[even_index]=creditcard_numbers[even_index]
even_index=even_index-1
total=0
for i in tmp:
total=total+i
if total%10 == 0:
return "valid"
else:
return "invalid"
for creditcard_numbers in a:
print creditcard_numbers
tmp=[0]*len(creditcard_numbers) #temporary list with zeros's
result=validate(creditcard_numbers,tmp)
print result
**OUTPUT :
[4, 0, 1, 2, 8, 8, 8, 8, 8, 8, 8, 8, 1, 8, 8, 1]
valid
[4, 0, 1, 2, 8, 8, 8, 8, 8, 8, 8, 8, 1, 8, 8, 2]
invalid
**
Here's a couple of ways. The first is a straight port to Python of the pseudo-code on the "Luhn algorithm" Wikipedia page (link). The second uses a lookup table to with the pre-computed doubled value of every other digit:
def checkLuhn(purportedCC):
sm = 0
nDigits = len(purportedCC)
parity = nDigits % 2
for i in range(nDigits):
digit = int(purportedCC[i])
if i % 2 == parity:
digit = digit * 2
if digit > 9:
digit = digit - 9
sm = sm + digit
return (sm % 10) == 0
def check(s):
lookup = [0,2,4,6,8,1,3,5,7,9]
digits = [int(c) for c in reversed(s)] # count odd/even from the right
odd = digits[::2]
even = digits[1::2]
total = sum(odd) + sum(lookup[c] for c in even)
return total % 10 == 0
cards = '1111222233334444','1111222233334445','01111222233334444'
for card in cards:
print(card,check(card))
print(card,checkLuhn(card))
Output (note if done correctly leading zeros don't affect the validation):
1111222233334444 True
1111222233334444 True
1111222233334445 False
1111222233334445 False
01111222233334444 True
01111222233334444 True