I'm working on a validator of credit cards. That sphere is new for me, so please, don't laugh:D
I'm trying to finish it without any libraries.
def creditCardValidation(creditcard):
creditcard = creditcard.replace( ' ', '' )
creditcard = [int(i) for i in creditcard]
evens = creditcard[::2]
odds = creditcard[1::2]
evens = [element * 2 for element in evens]
for j in evens:
if j >= 10:
j = [int(d) for d in str(j)]
for x in j:
evens.append(x)
for j in evens:
if j >= 10:
evens.remove(j)
return ((sum(evens) + sum(odds)) % 10 == 0)
creditCardValidation('1234 5678 9101 1213')
creditCardValidation('4561 2612 1234 5464')
creditCardValidation('4561 2612 1234 5467')
So the problem is in the array evens.
It returns
[2, 6, 14, 0, 2, 2, 1, 0, 1, 4, 1, 8]
[8, 4, 2, 2, 6, 12, 1, 2, 1, 0, 1, 2]
[8, 4, 2, 2, 6, 12, 1, 2, 1, 0, 1, 2]
It should return the same results except those which greater than 10. Everything works fine. Take a look at the first array, 18 deleted as well as 10, but 14 is not.
Removing while iterating over the array is not the best thing to do and will mostly result in skipping some elements in the array while iterating, so a safer way to do this
for j in evens:
if j >= 10:
evens.remove(j)
is to collect all the elements you want to remove in another list then subtract it from your original if you are using numpy arrrays or removing them one by one, as python lists has no subtraction operation defined to subtract one array from a another
to_remove = []
for j in evens:
if j >= 10:
to_remove.append(j)
for j in to_remove:
events.remove(j)
or you could whitelist instead of blacklisting
small_evens = []
for j in evens:
if j < 10:
small_evens.append(j)
# use small_evens and discard evens array
A couple of issues:
Python has zero indexed arrays, so evens[::2] is actually returning the first, third, etc. digit. Luhn's algo requires even digits (assuming 1 indexing) to be doubled.
You shouldn't modify a list you are iterating over.
You can simplify, removing a lot of the list creations:
def creditCardValidation(creditcard):
*creditcard, checkdigit = creditcard.replace(' ', '')
total = 0
for i, digit in enumerate(map(int, creditcard), 1):
if i % 2 == 0:
digit *= 2
total += digit // 10 # Will be zero for single digits
total += digit % 10
return 9*total % 10 == int(checkdigit)
In []:
creditCardValidation('1234 5678 9101 1213')
Out[]:
True
In []:
creditCardValidation('4561 2612 1234 5464')
Out[]:
False
Related
I am interested in finding the first and last index of the longest sequence of same-valued neighbours for a given list. The closest question I could find was: First and last index of a sequence, but this does not exactly answer my question.
So let's say for example:
a = [4, 6, 1, 0, 0, 0, 2, 4, 4, 1]
I would like to output to be
[3, 5]
Here is what I have come up with so far, and it works for this example. However, once the list changes to have a 0 somewhere before or after the sequence (non-neighbouring) it does not work anymore.
# Find distinct values of a
distinct = []
for x in a:
if x not in distinct:
distinct.append(x)
# Check which value has the longest sequence
countMax = 0
countNow = 1
num = 0
for i in a:
if a[i] == a[i+1]:
countNow += 1
num = i
else:
countNow = 1
if countNow > countMax:
countMax = countNow
longest = distinct[num-1]
# Find first index value of number with longest sequence
firstIndex = a.index(longest)
# Find last index value of number with longest sequence
a_reverse = a[::-1]
firstIndex_reverse = a_reverse.index(longest)
lastIndex = len(a) - 1 - firstIndex_reverse
print(firstIndex, lastIndex)
I don't know how better to find the first and last index for only the sequence in question.
I'd just iterate the list and keep track of everything:
a = [4, 6, 1, 0, 0, 0, 2, 4, 4, 4, 4, 4, 4, 1]
# indices
best_start = 0
best_end = 0
curr_start = 0
curr_end = 0
prev_val = a[0]
for (idx, curr_val) in enumerate(a[1:]):
curr_end = idx + 1 # +1 since slicing shifted everything
if prev_val == curr_val:
if curr_end - curr_start > best_end - best_start:
best_start = curr_start
best_end = curr_end
else:
curr_start = curr_end
prev_val = curr_val
print(best_start, best_end)
I'd like to sum the first element and last elements of a list, and then exclude those two numbers and repeat that process again until there is only one element in the list. Like this:
[5,4,3,2,1,6]
[11,5,5]
[16,5]
[21]
I used some methods but didn't work.
I am just a computer science student starting to python so help me out please guys.
Thank you.
Main logic of this answer is revolve around len of last list print. Lets break it in few points :
LOGIC :
1. Basically we need sum of first-ith and last-ith value for that we used this code:
l_u[-1][i] + l_u[-1][-i - 1]
2. Above point is only valid when lenght of last append list is even for odd-length we have to append this only at even poistion :
l_u[-1][i]
3. Among above two statement which is going to true this is done by this condition:
len(l_u[-1])%2 != 0 and i%2 != 0
CODE :
l = [5, 4, 3, 2, 1, 6]
l_u = [l]
condn = True
j = 0
while condn:
l_u.append([
l_u[-1][i] if len(l_u[-1]) % 2 != 0 and i % 2 != 0 else l_u[-1][i] +
l_u[-1][-i - 1] for i in range(
len(l_u[-1]) // 2 if len(l_u[-1]) % 2 == 0 else len(l_u[-1]) // 2 +
1)
])
if len(l_u[-1]) <= 1:
break
print(l_u)
OUTPUT :
[[5, 4, 3, 2, 1, 6], [11, 5, 5], [16, 5], [21]]
Suppose we need to transform an array of integers and then compute the sum.
The transformation is the following:
For each integer in the array, subtract the first subsequent integer that is equal or less than its value.
For example, the array:
[6, 1, 3, 4, 6, 2]
becomes
[5, 1, 1, 2, 4, 2]
because
6 > 1 so 6 - 1 = 5
nothing <= to 1 so 1 remains 1
3 > 2 so 3 - 2 = 1
4 > 2 so 4 - 2 = 2
6 > 2 so 6 - 2 = 4
nothing <= to 2 so 2 remains 2
so we sum [5, 1, 1, 2, 4, 2] = 15
I already have the answer below but apparently there is a more optimal method. My answer runs in quadratic time complexity (nested for loop) and I can't figure out how to optimize it.
prices = [6, 1, 3, 4, 6, 2]
results = []
counter = 0
num_prices = len(prices)
for each_item in prices:
flag = True
counter += 1
for each_num in range(counter, num_prices):
if each_item >= prices[each_num] and flag == True:
cost = each_item - prices[each_num]
results.append(cost)
flag = False
if flag == True:
results.append(each_item)
print(sum(results))
Can someone figure out how to answer this question faster than quadratic time complexity? I'm pretty sure this can be done only using 1 for loop but I don't know the data structure to use.
EDIT:
I might be mistaken... I just realized I could have added a break statement after flag = False and that would have saved me from a few unnecessary iterations. I took this question on a quiz and half the test cases said there was a more optimal method. They could have been referring to the break statement so maybe there isn't a faster method than using nested for loop
You can use a stack (implemented using a Python list). The algorithm is linear since each element is compared at most twice (one time with the next element, one time with the next number smaller or equals to it).
def adjusted_total(prices):
stack = []
total_substract = i = 0
n = len(prices)
while i < n:
if not stack or stack[-1] < prices[i]:
stack.append(prices[i])
i += 1
else:
stack.pop()
total_substract += prices[i]
return sum(prices) - total_substract
print(adjusted_total([6, 1, 3, 4, 6, 2]))
Output:
15
a simple way to do it with lists, albeit still quadratic..
p = [6, 1, 3, 4, 6, 2]
out= []
for i,val in zip(range(len(p)),p):
try:
out.append(val - p[[x <= val for x in p[i+1:]].index(True)+(i+1)])
except:
out.append(val)
sum(out) # equals 15
NUMPY APPROACH - honestly don't have alot of programming background so I'm not sure if its linear or not (depending on how the conditional masking works in the background) but still interesting
p = np.array([6, 1, 3, 4, 6, 2])
out = np.array([])
for i,val in zip(range(len(p)),p):
pp = p[i+1:]
try:
new = val - pp[pp<=val][0]
out = np.append(out,new)
except:
out = np.append(out,p[i])
out.sum() #equals 15
Problem:
On a given standard dial pad, what is the # of unique numbers that can be generated from jumping N times with the constraint that when you jump, you must move like the knight chess piece. You also cannot land on any invalid values like the X's but you may pass through them.
Dialer:
1 2 3
4 5 6
7 8 9
X 0 X
Very similar to this
Generate 10-digit number using a phone keypad
What I have so far but is crazy slow (Python 2.7)
jumpMap = {
1: [6,8],
2: [7,9],
3: [4,8],
4: [0, 3, 9],
5: [],
6: [0, 1, 7],
7: [2, 6],
8: [1, 3],
9: [2, 4],
0: [4, 6]
}
def findUnique(start, jumps):
if jumps == 1:
# Base case 1 jump
return len(jumpMap[start])
if start == 5:
return 0
sum = 0
for value in (jumpMap[start]):
sum = sum + findUnique(value, jumps-1)
return sum
I'm guessing the easiest way to optimize would to have some kind of memoization but I can't figure out how to use one given the problem constraints.
Let K(k, n) be the number of unique numbers of length n, starting with key k. Then, K(k, n+1) = sum(K(i, n)) where i ranges over the keys that it's possible to jump to from key k.
This can be calculated efficiently using dynamic programming; here's one way that takes O(n) time and O(1) space:
jumpMap = [map(int, x) for x in '46,68,79,48,039,,017,26,13,24'.split(',')]
def jumps(n):
K = [1] * 10
for _ in xrange(n):
K = [sum(K[j] for j in jumpMap[i]) for i in xrange(10)]
return sum(K)
for i in xrange(10):
print i, jumps(i)
Faster: it's possible to compute the answer in log(n) time and O(1) space. Let M be the 10 by 10 matrix with M[i,j] = 1 if it's possible to jump from i to j, and 0 otherwise. Then sum(M^n * ones(10, 1)) is the answer. The matrix power can be computed using exponentiation by squaring in log(n) time. Here's some code using numpy:
jumpMap = [map(int, x) for x in '46,68,79,48,039,,017,26,13,24'.split(',')]
M = numpy.matrix([[1 if j in jumpMap[i] else 0 for j in xrange(10)] for i in xrange(10)])
def jumps_mat(n):
return sum(M ** n * numpy.ones((10, 1)))[0,0]
for i in xrange(10):
print i, jumps_mat(i)
You can use the lru_cache, it will memoize calls:
from functools import lru_cache
jumpMap = {
1: [6,8],
2: [7,9],
3: [4,8],
4: [0, 3, 9],
5: [],
6: [0, 1, 7],
7: [2, 6],
8: [1, 3],
9: [2, 4],
0: [4, 6]
}
#lru_cache(maxsize=1000)
def findUnique(start, jumps):
if jumps == 1:
return len(jumpMap[start])
if start == 5:
return 0
sum = 0
for value in (jumpMap[start]):
sum = sum + findUnique(value, jumps-1)
return sum
This question already has answers here:
What is the most efficient way of finding all the factors of a number in Python?
(29 answers)
Closed 9 years ago.
This is the code I have right now. I can't get it to return the right results for the question.
def problem(n):
myList = [1,n]
for i in range(1,n):
result = int(n ** .5)
new = n/result
i = i + 1
myList.append(new)
return myList
Factors of n are all numbers that divide into n evenly. So i is a factor of n if n % i == 0.
You need to do is perform this test for each number from 1 to n, and if that condition is true append that number to your list.
If you have issues as you start to write this code, update your question with what you tried.
Note that the above approach is not the most efficient way to find factors, but it seems to me like this is just an exercise for a beginning programmer so a naive approach is expected.
There are a few problems with your code. First of all you do not need to increment i as your for loop already does that. Secondly, using some basic math principles you only need to go through a range of numbers up to the square root of your passed in number. I will leave the second part for you to play and experiment with.
def problem(n):
myList = []
for i in range(1, n+1):
if n % i == 0:
myList.append(i)
return myList
For a more advanced approach you can try list comprehensions which are very powerful but are usually better for smaller data sets.
def problem(n):
return [x for x in range(1, n+1) if n % x == 0]
You only need to iterate from 1 to n ** 0.5 + 1, and your factors will be all i's, and n/i's you pick up along the way.
For example: factors of 10:
We only need to iterate from 1 to 4
i = 1 => 10 % 1 == 0, so factors: i = 1, 10 / i = 10
i = 2 => 10 % 2 == 0, so factors: i = 2, 10 / i = 5
i = 3 => 10 % 3 != 0, no factors
We don't need to go any further, the answer is 1, 2, 5, 10.
def problem(n):
myList = []
for i in xrange(1, int(n ** 0.5 + 1)):
if n % i == 0:
if (i != n/i):
myList.append(i)
myList.append(n / i)
else:
myList.append(i)
return myList
Result:
>>> problem(10)
[1, 10, 2, 5]
>>> problem(12)
[1, 12, 2, 6, 3, 4]
>>> problem(77)
[1, 77, 7, 11]
>>> problem(4)
[1, 4, 2]
>>> problem(64)
[1, 64, 2, 32, 4, 16, 8]
>>> len(problem(10 ** 12))
169
use a list comprehension:
In [4]: num=120
In [5]: [x for x in range(2,int(num/2)+1) if num%x==0]
Out[5]: [2, 3, 4, 5, 6, 8, 10, 12, 15, 20, 24, 30, 40, 60]
In [6]: num=121
In [7]: [x for x in range(2,int(num/2)+1) if num%x==0]
Out[7]: [11]