Implementation of Luhn credit card algorithm











up vote
7
down vote

favorite
2












I've implemented Luhn's algorithm for checking credit card numbers.
My code works, but I wanted to learn about a more efficient and more Pythonic way of doing this.



def validate_credit_card_number(card_number):
#start writing your code here

#Step 1a - complete
temp_list=list(str(card_number))
my_list=
list1 = temp_list[-2::-2]
list2=temp_list[::-2]
list2 = [int (n) for n in list2]
#print(list2)
my_list=[int(n) for n in list1]
#print(my_list)
list1 = [int(n)*2 for n in list1]
t_list=list1

for el in list1:
sum_res=0

if el>9:
idx = list1.index(el)
t_list.pop(idx)

while el:
rem = el%10
sum_res+=rem
el = el//10
t_list.insert(idx, sum_res)
#print(t_list)

#step 1b

list1_sum=sum(t_list)
list2_sum = sum(list2)
#print(b_list)
final_sum = list1_sum+ list2_sum
#print(final_sum)

if final_sum%10==0:
return True
return False

card_number= 1456734512345698 #4539869650133101 #1456734512345698 # #5239512608615007

result=validate_credit_card_number(card_number)
if(result):
print("credit card number is valid")
else:
print("credit card number is invalid")









share|improve this question









New contributor




HackersInside is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.




















  • (Welcome to Code Review!) (This question seems to be getting smoother by the edit…)
    – greybeard
    4 hours ago















up vote
7
down vote

favorite
2












I've implemented Luhn's algorithm for checking credit card numbers.
My code works, but I wanted to learn about a more efficient and more Pythonic way of doing this.



def validate_credit_card_number(card_number):
#start writing your code here

#Step 1a - complete
temp_list=list(str(card_number))
my_list=
list1 = temp_list[-2::-2]
list2=temp_list[::-2]
list2 = [int (n) for n in list2]
#print(list2)
my_list=[int(n) for n in list1]
#print(my_list)
list1 = [int(n)*2 for n in list1]
t_list=list1

for el in list1:
sum_res=0

if el>9:
idx = list1.index(el)
t_list.pop(idx)

while el:
rem = el%10
sum_res+=rem
el = el//10
t_list.insert(idx, sum_res)
#print(t_list)

#step 1b

list1_sum=sum(t_list)
list2_sum = sum(list2)
#print(b_list)
final_sum = list1_sum+ list2_sum
#print(final_sum)

if final_sum%10==0:
return True
return False

card_number= 1456734512345698 #4539869650133101 #1456734512345698 # #5239512608615007

result=validate_credit_card_number(card_number)
if(result):
print("credit card number is valid")
else:
print("credit card number is invalid")









share|improve this question









New contributor




HackersInside is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.




















  • (Welcome to Code Review!) (This question seems to be getting smoother by the edit…)
    – greybeard
    4 hours ago













up vote
7
down vote

favorite
2









up vote
7
down vote

favorite
2






2





I've implemented Luhn's algorithm for checking credit card numbers.
My code works, but I wanted to learn about a more efficient and more Pythonic way of doing this.



def validate_credit_card_number(card_number):
#start writing your code here

#Step 1a - complete
temp_list=list(str(card_number))
my_list=
list1 = temp_list[-2::-2]
list2=temp_list[::-2]
list2 = [int (n) for n in list2]
#print(list2)
my_list=[int(n) for n in list1]
#print(my_list)
list1 = [int(n)*2 for n in list1]
t_list=list1

for el in list1:
sum_res=0

if el>9:
idx = list1.index(el)
t_list.pop(idx)

while el:
rem = el%10
sum_res+=rem
el = el//10
t_list.insert(idx, sum_res)
#print(t_list)

#step 1b

list1_sum=sum(t_list)
list2_sum = sum(list2)
#print(b_list)
final_sum = list1_sum+ list2_sum
#print(final_sum)

if final_sum%10==0:
return True
return False

card_number= 1456734512345698 #4539869650133101 #1456734512345698 # #5239512608615007

result=validate_credit_card_number(card_number)
if(result):
print("credit card number is valid")
else:
print("credit card number is invalid")









share|improve this question









New contributor




HackersInside is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.











I've implemented Luhn's algorithm for checking credit card numbers.
My code works, but I wanted to learn about a more efficient and more Pythonic way of doing this.



def validate_credit_card_number(card_number):
#start writing your code here

#Step 1a - complete
temp_list=list(str(card_number))
my_list=
list1 = temp_list[-2::-2]
list2=temp_list[::-2]
list2 = [int (n) for n in list2]
#print(list2)
my_list=[int(n) for n in list1]
#print(my_list)
list1 = [int(n)*2 for n in list1]
t_list=list1

for el in list1:
sum_res=0

if el>9:
idx = list1.index(el)
t_list.pop(idx)

while el:
rem = el%10
sum_res+=rem
el = el//10
t_list.insert(idx, sum_res)
#print(t_list)

#step 1b

list1_sum=sum(t_list)
list2_sum = sum(list2)
#print(b_list)
final_sum = list1_sum+ list2_sum
#print(final_sum)

if final_sum%10==0:
return True
return False

card_number= 1456734512345698 #4539869650133101 #1456734512345698 # #5239512608615007

result=validate_credit_card_number(card_number)
if(result):
print("credit card number is valid")
else:
print("credit card number is invalid")






python performance checksum






share|improve this question









New contributor




HackersInside is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.











share|improve this question









New contributor




HackersInside is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.









share|improve this question




share|improve this question








edited 9 hours ago









200_success

128k15149412




128k15149412






New contributor




HackersInside is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.









asked 9 hours ago









HackersInside

383




383




New contributor




HackersInside is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.





New contributor





HackersInside is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.






HackersInside is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.












  • (Welcome to Code Review!) (This question seems to be getting smoother by the edit…)
    – greybeard
    4 hours ago


















  • (Welcome to Code Review!) (This question seems to be getting smoother by the edit…)
    – greybeard
    4 hours ago
















(Welcome to Code Review!) (This question seems to be getting smoother by the edit…)
– greybeard
4 hours ago




(Welcome to Code Review!) (This question seems to be getting smoother by the edit…)
– greybeard
4 hours ago










2 Answers
2






active

oldest

votes

















up vote
7
down vote



accepted










Style



Python has a style guide called PEP 8. It is a good habit to try to follow it.



In your case, that would mean fixing the missing whitespaces, removing parenthesis in if(result).



Also, you could get rid of old commented code and add a proper docstring if you want to describe the behavior of the function.



Tests



It could be a good idea to write tests before trying to improve your code.



I wrote a very simple code but you could get this chance to dive into unit testing frameworks:



TESTS = [
(1456734512345698, False),
(4539869650133101, True),
(1456734512345698, False),
(5239512608615007, True),
]

for (card_number, expected_valid) in TESTS:
valid = validate_credit_card_number(card_number)
assert valid == expected_valid


Useless test



At the end of the function, you can return directly:



return final_sum % 10 == 0


Useless variables



The my_list variable is not required.



Also, we can take this chance to get rid of the variables at the end of the function:



return (sum(t_list) + sum(list2)) % 10 == 0


Conversion of card_number



At the beginning of the function, you could convert the parts of card_number directly to integer so that you do it in a single place.
Also, that removed the need to the call of list. We just have:



temp_list = [int(c) for c in str(card_number)]


And we can get rid of the line:



list2 = [int (n) for n in list2]


At this stage, the code looks like:



def validate_credit_card_number(card_number):
temp_list = [int(c) for c in str(card_number)]

list1 = temp_list[-2::-2]
list1 = [2 * n for n in list1]

list2 = temp_list[::-2]

t_list = list1

for el in list1:
sum_res = 0

if el > 9:
idx = list1.index(el)
t_list.pop(idx)

while el:
rem = el % 10
sum_res += rem
el = el // 10
t_list.insert(idx, sum_res)

return (sum(t_list) + sum(list2)) % 10 == 0


Yet another useless variable



t_list aliases list1 (I am not sure if this is intended if if you were planning to have a copy of list1). Whenever you update the list through one variable, the other is affected as well. I highly recommend Ned Batchelder's talk about names and values.



In your case, we can get rid of t_list completely without changing the behavior of the function.



Simplify list logic



You go through multiple steps to modify list1 (or t_list) : index, pop, index. These steps are more expensive/complicated than required. At the end of the day, you do not care about list1, you just want its final sum. You could keep track of the sum directly:



sum1 = 0
for el in list1:
if el > 9:
sum_res = 0
while el:
rem = el % 10
sum_res += rem
el = el // 10
sum1 += sum_res
else:
sum1 += el

return (sum1 + sum(list2)) % 10 == 0


We can take this chance to perform the multiplication in the loop to remove a list comprehension.



Also, we can initialise the sum with sum(list2) so that we don't have to add them at the end:



def validate_credit_card_number(card_number):
temp_list = [int(c) for c in str(card_number)]

list1 = temp_list[-2::-2]
list2 = temp_list[::-2]

total_sum = sum(list2)
for el in list1:
el *= 2
if el > 9:
sum_res = 0
while el:
rem = el % 10
sum_res += rem
el = el // 10
total_sum += sum_res
else:
total_sum += el

return total_sum % 10 == 0


Math logic



The code uses 10 (the base used for computations) everywhere except for one 9 which seems unexpected. You could write: el >= 10 instead.



Also, that check is not required because the logic applies exactly the same way for elements smaller than 10:



for el in list1:
el *= 2
sum_res = 0
while el:
rem = el % 10
sum_res += rem
el = el // 10
total_sum += sum_res


Also, you could use el //= 10 but you can get the best ouf of the Python builtins by using divmod returning both the quotient and the remainder:



    while el:
el, rem = divmod(el, 10)
sum_res += rem
total_sum += sum_res


Then, it becomes clear that the variable sum_res is not really required as we could use total_sum instead:



    while el:
el, rem = divmod(el, 10)
total_sum += rem


"Final" code



def validate_credit_card_number(card_number):
temp_list = [int(c) for c in str(card_number)]

list1 = temp_list[-2::-2]
list2 = temp_list[::-2]

total_sum = sum(list2)
for el in list1:
el *= 2
while el:
el, rem = divmod(el, 10)
total_sum += rem

return total_sum % 10 == 0

TESTS = [
(1456734512345698, False),
(4539869650133101, True),
(1456734512345698, False),
(5239512608615007, True),
]

for (card_number, expected_valid) in TESTS:
valid = validate_credit_card_number(card_number)
assert valid == expected_valid


More simplification



Thinking about it, things can still be simplified a lot.
What you are doing with the while loop can be performed using str conversion:



total_sum = sum(list2)
for el in list1:
total_sum += sum(int(c) for c in str(2 * el))


Going further (too far?), this leads to:



def validate_credit_card_number(card_number):
temp_list = [int(c) for c in str(card_number)]

list1 = temp_list[-2::-2]
list2 = temp_list[::-2]

total_sum = sum(list2) + sum(sum(int(c) for c in str(2 * el)) for el in list1)
return total_sum % 10 == 0





share|improve this answer



















  • 1




    Wow. I'm overwhelmed by your answer. Thanks
    – HackersInside
    7 hours ago












  • @HackersInside actually, I have other ideas that could somehow improve the solution. I'll try to update the answer when I am on a computer
    – Josay
    6 hours ago










  • Sure that would be amazing. Thanks
    – HackersInside
    6 hours ago


















up vote
2
down vote













I assume that card_number is an integer. As such, you should not convert it to a str, nor convert it to a list. You should be doing integer operations only, not list operations.



For your learning purposes, I won't rewrite the algorithm for you, but try to rewrite it such that it's represented as a loop over the credit card number, which successively gets divided by 10.






share|improve this answer





















  • How am I supposed to iterate over a number, even if I break the number to digits, I will have to store it in a list for further processing.
    – HackersInside
    9 hours ago










  • Nope. Successively divide the number by 10 and work with the modulus.
    – Reinderien
    9 hours ago










  • Ok, I will try that out. However, I was wondering what would be the cons of converting it to a list/str?
    – HackersInside
    9 hours ago










  • It's slower and uses (slightly) more memory.
    – Reinderien
    9 hours ago










  • Ok, thanks. I will work on the code
    – HackersInside
    8 hours ago











Your Answer





StackExchange.ifUsing("editor", function () {
return StackExchange.using("mathjaxEditing", function () {
StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
});
});
}, "mathjax-editing");

StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "196"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});






HackersInside is a new contributor. Be nice, and check out our Code of Conduct.










draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f209680%2fimplementation-of-luhn-credit-card-algorithm%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























2 Answers
2






active

oldest

votes








2 Answers
2






active

oldest

votes









active

oldest

votes






active

oldest

votes








up vote
7
down vote



accepted










Style



Python has a style guide called PEP 8. It is a good habit to try to follow it.



In your case, that would mean fixing the missing whitespaces, removing parenthesis in if(result).



Also, you could get rid of old commented code and add a proper docstring if you want to describe the behavior of the function.



Tests



It could be a good idea to write tests before trying to improve your code.



I wrote a very simple code but you could get this chance to dive into unit testing frameworks:



TESTS = [
(1456734512345698, False),
(4539869650133101, True),
(1456734512345698, False),
(5239512608615007, True),
]

for (card_number, expected_valid) in TESTS:
valid = validate_credit_card_number(card_number)
assert valid == expected_valid


Useless test



At the end of the function, you can return directly:



return final_sum % 10 == 0


Useless variables



The my_list variable is not required.



Also, we can take this chance to get rid of the variables at the end of the function:



return (sum(t_list) + sum(list2)) % 10 == 0


Conversion of card_number



At the beginning of the function, you could convert the parts of card_number directly to integer so that you do it in a single place.
Also, that removed the need to the call of list. We just have:



temp_list = [int(c) for c in str(card_number)]


And we can get rid of the line:



list2 = [int (n) for n in list2]


At this stage, the code looks like:



def validate_credit_card_number(card_number):
temp_list = [int(c) for c in str(card_number)]

list1 = temp_list[-2::-2]
list1 = [2 * n for n in list1]

list2 = temp_list[::-2]

t_list = list1

for el in list1:
sum_res = 0

if el > 9:
idx = list1.index(el)
t_list.pop(idx)

while el:
rem = el % 10
sum_res += rem
el = el // 10
t_list.insert(idx, sum_res)

return (sum(t_list) + sum(list2)) % 10 == 0


Yet another useless variable



t_list aliases list1 (I am not sure if this is intended if if you were planning to have a copy of list1). Whenever you update the list through one variable, the other is affected as well. I highly recommend Ned Batchelder's talk about names and values.



In your case, we can get rid of t_list completely without changing the behavior of the function.



Simplify list logic



You go through multiple steps to modify list1 (or t_list) : index, pop, index. These steps are more expensive/complicated than required. At the end of the day, you do not care about list1, you just want its final sum. You could keep track of the sum directly:



sum1 = 0
for el in list1:
if el > 9:
sum_res = 0
while el:
rem = el % 10
sum_res += rem
el = el // 10
sum1 += sum_res
else:
sum1 += el

return (sum1 + sum(list2)) % 10 == 0


We can take this chance to perform the multiplication in the loop to remove a list comprehension.



Also, we can initialise the sum with sum(list2) so that we don't have to add them at the end:



def validate_credit_card_number(card_number):
temp_list = [int(c) for c in str(card_number)]

list1 = temp_list[-2::-2]
list2 = temp_list[::-2]

total_sum = sum(list2)
for el in list1:
el *= 2
if el > 9:
sum_res = 0
while el:
rem = el % 10
sum_res += rem
el = el // 10
total_sum += sum_res
else:
total_sum += el

return total_sum % 10 == 0


Math logic



The code uses 10 (the base used for computations) everywhere except for one 9 which seems unexpected. You could write: el >= 10 instead.



Also, that check is not required because the logic applies exactly the same way for elements smaller than 10:



for el in list1:
el *= 2
sum_res = 0
while el:
rem = el % 10
sum_res += rem
el = el // 10
total_sum += sum_res


Also, you could use el //= 10 but you can get the best ouf of the Python builtins by using divmod returning both the quotient and the remainder:



    while el:
el, rem = divmod(el, 10)
sum_res += rem
total_sum += sum_res


Then, it becomes clear that the variable sum_res is not really required as we could use total_sum instead:



    while el:
el, rem = divmod(el, 10)
total_sum += rem


"Final" code



def validate_credit_card_number(card_number):
temp_list = [int(c) for c in str(card_number)]

list1 = temp_list[-2::-2]
list2 = temp_list[::-2]

total_sum = sum(list2)
for el in list1:
el *= 2
while el:
el, rem = divmod(el, 10)
total_sum += rem

return total_sum % 10 == 0

TESTS = [
(1456734512345698, False),
(4539869650133101, True),
(1456734512345698, False),
(5239512608615007, True),
]

for (card_number, expected_valid) in TESTS:
valid = validate_credit_card_number(card_number)
assert valid == expected_valid


More simplification



Thinking about it, things can still be simplified a lot.
What you are doing with the while loop can be performed using str conversion:



total_sum = sum(list2)
for el in list1:
total_sum += sum(int(c) for c in str(2 * el))


Going further (too far?), this leads to:



def validate_credit_card_number(card_number):
temp_list = [int(c) for c in str(card_number)]

list1 = temp_list[-2::-2]
list2 = temp_list[::-2]

total_sum = sum(list2) + sum(sum(int(c) for c in str(2 * el)) for el in list1)
return total_sum % 10 == 0





share|improve this answer



















  • 1




    Wow. I'm overwhelmed by your answer. Thanks
    – HackersInside
    7 hours ago












  • @HackersInside actually, I have other ideas that could somehow improve the solution. I'll try to update the answer when I am on a computer
    – Josay
    6 hours ago










  • Sure that would be amazing. Thanks
    – HackersInside
    6 hours ago















up vote
7
down vote



accepted










Style



Python has a style guide called PEP 8. It is a good habit to try to follow it.



In your case, that would mean fixing the missing whitespaces, removing parenthesis in if(result).



Also, you could get rid of old commented code and add a proper docstring if you want to describe the behavior of the function.



Tests



It could be a good idea to write tests before trying to improve your code.



I wrote a very simple code but you could get this chance to dive into unit testing frameworks:



TESTS = [
(1456734512345698, False),
(4539869650133101, True),
(1456734512345698, False),
(5239512608615007, True),
]

for (card_number, expected_valid) in TESTS:
valid = validate_credit_card_number(card_number)
assert valid == expected_valid


Useless test



At the end of the function, you can return directly:



return final_sum % 10 == 0


Useless variables



The my_list variable is not required.



Also, we can take this chance to get rid of the variables at the end of the function:



return (sum(t_list) + sum(list2)) % 10 == 0


Conversion of card_number



At the beginning of the function, you could convert the parts of card_number directly to integer so that you do it in a single place.
Also, that removed the need to the call of list. We just have:



temp_list = [int(c) for c in str(card_number)]


And we can get rid of the line:



list2 = [int (n) for n in list2]


At this stage, the code looks like:



def validate_credit_card_number(card_number):
temp_list = [int(c) for c in str(card_number)]

list1 = temp_list[-2::-2]
list1 = [2 * n for n in list1]

list2 = temp_list[::-2]

t_list = list1

for el in list1:
sum_res = 0

if el > 9:
idx = list1.index(el)
t_list.pop(idx)

while el:
rem = el % 10
sum_res += rem
el = el // 10
t_list.insert(idx, sum_res)

return (sum(t_list) + sum(list2)) % 10 == 0


Yet another useless variable



t_list aliases list1 (I am not sure if this is intended if if you were planning to have a copy of list1). Whenever you update the list through one variable, the other is affected as well. I highly recommend Ned Batchelder's talk about names and values.



In your case, we can get rid of t_list completely without changing the behavior of the function.



Simplify list logic



You go through multiple steps to modify list1 (or t_list) : index, pop, index. These steps are more expensive/complicated than required. At the end of the day, you do not care about list1, you just want its final sum. You could keep track of the sum directly:



sum1 = 0
for el in list1:
if el > 9:
sum_res = 0
while el:
rem = el % 10
sum_res += rem
el = el // 10
sum1 += sum_res
else:
sum1 += el

return (sum1 + sum(list2)) % 10 == 0


We can take this chance to perform the multiplication in the loop to remove a list comprehension.



Also, we can initialise the sum with sum(list2) so that we don't have to add them at the end:



def validate_credit_card_number(card_number):
temp_list = [int(c) for c in str(card_number)]

list1 = temp_list[-2::-2]
list2 = temp_list[::-2]

total_sum = sum(list2)
for el in list1:
el *= 2
if el > 9:
sum_res = 0
while el:
rem = el % 10
sum_res += rem
el = el // 10
total_sum += sum_res
else:
total_sum += el

return total_sum % 10 == 0


Math logic



The code uses 10 (the base used for computations) everywhere except for one 9 which seems unexpected. You could write: el >= 10 instead.



Also, that check is not required because the logic applies exactly the same way for elements smaller than 10:



for el in list1:
el *= 2
sum_res = 0
while el:
rem = el % 10
sum_res += rem
el = el // 10
total_sum += sum_res


Also, you could use el //= 10 but you can get the best ouf of the Python builtins by using divmod returning both the quotient and the remainder:



    while el:
el, rem = divmod(el, 10)
sum_res += rem
total_sum += sum_res


Then, it becomes clear that the variable sum_res is not really required as we could use total_sum instead:



    while el:
el, rem = divmod(el, 10)
total_sum += rem


"Final" code



def validate_credit_card_number(card_number):
temp_list = [int(c) for c in str(card_number)]

list1 = temp_list[-2::-2]
list2 = temp_list[::-2]

total_sum = sum(list2)
for el in list1:
el *= 2
while el:
el, rem = divmod(el, 10)
total_sum += rem

return total_sum % 10 == 0

TESTS = [
(1456734512345698, False),
(4539869650133101, True),
(1456734512345698, False),
(5239512608615007, True),
]

for (card_number, expected_valid) in TESTS:
valid = validate_credit_card_number(card_number)
assert valid == expected_valid


More simplification



Thinking about it, things can still be simplified a lot.
What you are doing with the while loop can be performed using str conversion:



total_sum = sum(list2)
for el in list1:
total_sum += sum(int(c) for c in str(2 * el))


Going further (too far?), this leads to:



def validate_credit_card_number(card_number):
temp_list = [int(c) for c in str(card_number)]

list1 = temp_list[-2::-2]
list2 = temp_list[::-2]

total_sum = sum(list2) + sum(sum(int(c) for c in str(2 * el)) for el in list1)
return total_sum % 10 == 0





share|improve this answer



















  • 1




    Wow. I'm overwhelmed by your answer. Thanks
    – HackersInside
    7 hours ago












  • @HackersInside actually, I have other ideas that could somehow improve the solution. I'll try to update the answer when I am on a computer
    – Josay
    6 hours ago










  • Sure that would be amazing. Thanks
    – HackersInside
    6 hours ago













up vote
7
down vote



accepted







up vote
7
down vote



accepted






Style



Python has a style guide called PEP 8. It is a good habit to try to follow it.



In your case, that would mean fixing the missing whitespaces, removing parenthesis in if(result).



Also, you could get rid of old commented code and add a proper docstring if you want to describe the behavior of the function.



Tests



It could be a good idea to write tests before trying to improve your code.



I wrote a very simple code but you could get this chance to dive into unit testing frameworks:



TESTS = [
(1456734512345698, False),
(4539869650133101, True),
(1456734512345698, False),
(5239512608615007, True),
]

for (card_number, expected_valid) in TESTS:
valid = validate_credit_card_number(card_number)
assert valid == expected_valid


Useless test



At the end of the function, you can return directly:



return final_sum % 10 == 0


Useless variables



The my_list variable is not required.



Also, we can take this chance to get rid of the variables at the end of the function:



return (sum(t_list) + sum(list2)) % 10 == 0


Conversion of card_number



At the beginning of the function, you could convert the parts of card_number directly to integer so that you do it in a single place.
Also, that removed the need to the call of list. We just have:



temp_list = [int(c) for c in str(card_number)]


And we can get rid of the line:



list2 = [int (n) for n in list2]


At this stage, the code looks like:



def validate_credit_card_number(card_number):
temp_list = [int(c) for c in str(card_number)]

list1 = temp_list[-2::-2]
list1 = [2 * n for n in list1]

list2 = temp_list[::-2]

t_list = list1

for el in list1:
sum_res = 0

if el > 9:
idx = list1.index(el)
t_list.pop(idx)

while el:
rem = el % 10
sum_res += rem
el = el // 10
t_list.insert(idx, sum_res)

return (sum(t_list) + sum(list2)) % 10 == 0


Yet another useless variable



t_list aliases list1 (I am not sure if this is intended if if you were planning to have a copy of list1). Whenever you update the list through one variable, the other is affected as well. I highly recommend Ned Batchelder's talk about names and values.



In your case, we can get rid of t_list completely without changing the behavior of the function.



Simplify list logic



You go through multiple steps to modify list1 (or t_list) : index, pop, index. These steps are more expensive/complicated than required. At the end of the day, you do not care about list1, you just want its final sum. You could keep track of the sum directly:



sum1 = 0
for el in list1:
if el > 9:
sum_res = 0
while el:
rem = el % 10
sum_res += rem
el = el // 10
sum1 += sum_res
else:
sum1 += el

return (sum1 + sum(list2)) % 10 == 0


We can take this chance to perform the multiplication in the loop to remove a list comprehension.



Also, we can initialise the sum with sum(list2) so that we don't have to add them at the end:



def validate_credit_card_number(card_number):
temp_list = [int(c) for c in str(card_number)]

list1 = temp_list[-2::-2]
list2 = temp_list[::-2]

total_sum = sum(list2)
for el in list1:
el *= 2
if el > 9:
sum_res = 0
while el:
rem = el % 10
sum_res += rem
el = el // 10
total_sum += sum_res
else:
total_sum += el

return total_sum % 10 == 0


Math logic



The code uses 10 (the base used for computations) everywhere except for one 9 which seems unexpected. You could write: el >= 10 instead.



Also, that check is not required because the logic applies exactly the same way for elements smaller than 10:



for el in list1:
el *= 2
sum_res = 0
while el:
rem = el % 10
sum_res += rem
el = el // 10
total_sum += sum_res


Also, you could use el //= 10 but you can get the best ouf of the Python builtins by using divmod returning both the quotient and the remainder:



    while el:
el, rem = divmod(el, 10)
sum_res += rem
total_sum += sum_res


Then, it becomes clear that the variable sum_res is not really required as we could use total_sum instead:



    while el:
el, rem = divmod(el, 10)
total_sum += rem


"Final" code



def validate_credit_card_number(card_number):
temp_list = [int(c) for c in str(card_number)]

list1 = temp_list[-2::-2]
list2 = temp_list[::-2]

total_sum = sum(list2)
for el in list1:
el *= 2
while el:
el, rem = divmod(el, 10)
total_sum += rem

return total_sum % 10 == 0

TESTS = [
(1456734512345698, False),
(4539869650133101, True),
(1456734512345698, False),
(5239512608615007, True),
]

for (card_number, expected_valid) in TESTS:
valid = validate_credit_card_number(card_number)
assert valid == expected_valid


More simplification



Thinking about it, things can still be simplified a lot.
What you are doing with the while loop can be performed using str conversion:



total_sum = sum(list2)
for el in list1:
total_sum += sum(int(c) for c in str(2 * el))


Going further (too far?), this leads to:



def validate_credit_card_number(card_number):
temp_list = [int(c) for c in str(card_number)]

list1 = temp_list[-2::-2]
list2 = temp_list[::-2]

total_sum = sum(list2) + sum(sum(int(c) for c in str(2 * el)) for el in list1)
return total_sum % 10 == 0





share|improve this answer














Style



Python has a style guide called PEP 8. It is a good habit to try to follow it.



In your case, that would mean fixing the missing whitespaces, removing parenthesis in if(result).



Also, you could get rid of old commented code and add a proper docstring if you want to describe the behavior of the function.



Tests



It could be a good idea to write tests before trying to improve your code.



I wrote a very simple code but you could get this chance to dive into unit testing frameworks:



TESTS = [
(1456734512345698, False),
(4539869650133101, True),
(1456734512345698, False),
(5239512608615007, True),
]

for (card_number, expected_valid) in TESTS:
valid = validate_credit_card_number(card_number)
assert valid == expected_valid


Useless test



At the end of the function, you can return directly:



return final_sum % 10 == 0


Useless variables



The my_list variable is not required.



Also, we can take this chance to get rid of the variables at the end of the function:



return (sum(t_list) + sum(list2)) % 10 == 0


Conversion of card_number



At the beginning of the function, you could convert the parts of card_number directly to integer so that you do it in a single place.
Also, that removed the need to the call of list. We just have:



temp_list = [int(c) for c in str(card_number)]


And we can get rid of the line:



list2 = [int (n) for n in list2]


At this stage, the code looks like:



def validate_credit_card_number(card_number):
temp_list = [int(c) for c in str(card_number)]

list1 = temp_list[-2::-2]
list1 = [2 * n for n in list1]

list2 = temp_list[::-2]

t_list = list1

for el in list1:
sum_res = 0

if el > 9:
idx = list1.index(el)
t_list.pop(idx)

while el:
rem = el % 10
sum_res += rem
el = el // 10
t_list.insert(idx, sum_res)

return (sum(t_list) + sum(list2)) % 10 == 0


Yet another useless variable



t_list aliases list1 (I am not sure if this is intended if if you were planning to have a copy of list1). Whenever you update the list through one variable, the other is affected as well. I highly recommend Ned Batchelder's talk about names and values.



In your case, we can get rid of t_list completely without changing the behavior of the function.



Simplify list logic



You go through multiple steps to modify list1 (or t_list) : index, pop, index. These steps are more expensive/complicated than required. At the end of the day, you do not care about list1, you just want its final sum. You could keep track of the sum directly:



sum1 = 0
for el in list1:
if el > 9:
sum_res = 0
while el:
rem = el % 10
sum_res += rem
el = el // 10
sum1 += sum_res
else:
sum1 += el

return (sum1 + sum(list2)) % 10 == 0


We can take this chance to perform the multiplication in the loop to remove a list comprehension.



Also, we can initialise the sum with sum(list2) so that we don't have to add them at the end:



def validate_credit_card_number(card_number):
temp_list = [int(c) for c in str(card_number)]

list1 = temp_list[-2::-2]
list2 = temp_list[::-2]

total_sum = sum(list2)
for el in list1:
el *= 2
if el > 9:
sum_res = 0
while el:
rem = el % 10
sum_res += rem
el = el // 10
total_sum += sum_res
else:
total_sum += el

return total_sum % 10 == 0


Math logic



The code uses 10 (the base used for computations) everywhere except for one 9 which seems unexpected. You could write: el >= 10 instead.



Also, that check is not required because the logic applies exactly the same way for elements smaller than 10:



for el in list1:
el *= 2
sum_res = 0
while el:
rem = el % 10
sum_res += rem
el = el // 10
total_sum += sum_res


Also, you could use el //= 10 but you can get the best ouf of the Python builtins by using divmod returning both the quotient and the remainder:



    while el:
el, rem = divmod(el, 10)
sum_res += rem
total_sum += sum_res


Then, it becomes clear that the variable sum_res is not really required as we could use total_sum instead:



    while el:
el, rem = divmod(el, 10)
total_sum += rem


"Final" code



def validate_credit_card_number(card_number):
temp_list = [int(c) for c in str(card_number)]

list1 = temp_list[-2::-2]
list2 = temp_list[::-2]

total_sum = sum(list2)
for el in list1:
el *= 2
while el:
el, rem = divmod(el, 10)
total_sum += rem

return total_sum % 10 == 0

TESTS = [
(1456734512345698, False),
(4539869650133101, True),
(1456734512345698, False),
(5239512608615007, True),
]

for (card_number, expected_valid) in TESTS:
valid = validate_credit_card_number(card_number)
assert valid == expected_valid


More simplification



Thinking about it, things can still be simplified a lot.
What you are doing with the while loop can be performed using str conversion:



total_sum = sum(list2)
for el in list1:
total_sum += sum(int(c) for c in str(2 * el))


Going further (too far?), this leads to:



def validate_credit_card_number(card_number):
temp_list = [int(c) for c in str(card_number)]

list1 = temp_list[-2::-2]
list2 = temp_list[::-2]

total_sum = sum(list2) + sum(sum(int(c) for c in str(2 * el)) for el in list1)
return total_sum % 10 == 0






share|improve this answer














share|improve this answer



share|improve this answer








edited 7 hours ago

























answered 7 hours ago









Josay

24.8k13783




24.8k13783








  • 1




    Wow. I'm overwhelmed by your answer. Thanks
    – HackersInside
    7 hours ago












  • @HackersInside actually, I have other ideas that could somehow improve the solution. I'll try to update the answer when I am on a computer
    – Josay
    6 hours ago










  • Sure that would be amazing. Thanks
    – HackersInside
    6 hours ago














  • 1




    Wow. I'm overwhelmed by your answer. Thanks
    – HackersInside
    7 hours ago












  • @HackersInside actually, I have other ideas that could somehow improve the solution. I'll try to update the answer when I am on a computer
    – Josay
    6 hours ago










  • Sure that would be amazing. Thanks
    – HackersInside
    6 hours ago








1




1




Wow. I'm overwhelmed by your answer. Thanks
– HackersInside
7 hours ago






Wow. I'm overwhelmed by your answer. Thanks
– HackersInside
7 hours ago














@HackersInside actually, I have other ideas that could somehow improve the solution. I'll try to update the answer when I am on a computer
– Josay
6 hours ago




@HackersInside actually, I have other ideas that could somehow improve the solution. I'll try to update the answer when I am on a computer
– Josay
6 hours ago












Sure that would be amazing. Thanks
– HackersInside
6 hours ago




Sure that would be amazing. Thanks
– HackersInside
6 hours ago












up vote
2
down vote













I assume that card_number is an integer. As such, you should not convert it to a str, nor convert it to a list. You should be doing integer operations only, not list operations.



For your learning purposes, I won't rewrite the algorithm for you, but try to rewrite it such that it's represented as a loop over the credit card number, which successively gets divided by 10.






share|improve this answer





















  • How am I supposed to iterate over a number, even if I break the number to digits, I will have to store it in a list for further processing.
    – HackersInside
    9 hours ago










  • Nope. Successively divide the number by 10 and work with the modulus.
    – Reinderien
    9 hours ago










  • Ok, I will try that out. However, I was wondering what would be the cons of converting it to a list/str?
    – HackersInside
    9 hours ago










  • It's slower and uses (slightly) more memory.
    – Reinderien
    9 hours ago










  • Ok, thanks. I will work on the code
    – HackersInside
    8 hours ago















up vote
2
down vote













I assume that card_number is an integer. As such, you should not convert it to a str, nor convert it to a list. You should be doing integer operations only, not list operations.



For your learning purposes, I won't rewrite the algorithm for you, but try to rewrite it such that it's represented as a loop over the credit card number, which successively gets divided by 10.






share|improve this answer





















  • How am I supposed to iterate over a number, even if I break the number to digits, I will have to store it in a list for further processing.
    – HackersInside
    9 hours ago










  • Nope. Successively divide the number by 10 and work with the modulus.
    – Reinderien
    9 hours ago










  • Ok, I will try that out. However, I was wondering what would be the cons of converting it to a list/str?
    – HackersInside
    9 hours ago










  • It's slower and uses (slightly) more memory.
    – Reinderien
    9 hours ago










  • Ok, thanks. I will work on the code
    – HackersInside
    8 hours ago













up vote
2
down vote










up vote
2
down vote









I assume that card_number is an integer. As such, you should not convert it to a str, nor convert it to a list. You should be doing integer operations only, not list operations.



For your learning purposes, I won't rewrite the algorithm for you, but try to rewrite it such that it's represented as a loop over the credit card number, which successively gets divided by 10.






share|improve this answer












I assume that card_number is an integer. As such, you should not convert it to a str, nor convert it to a list. You should be doing integer operations only, not list operations.



For your learning purposes, I won't rewrite the algorithm for you, but try to rewrite it such that it's represented as a loop over the credit card number, which successively gets divided by 10.







share|improve this answer












share|improve this answer



share|improve this answer










answered 9 hours ago









Reinderien

1,984616




1,984616












  • How am I supposed to iterate over a number, even if I break the number to digits, I will have to store it in a list for further processing.
    – HackersInside
    9 hours ago










  • Nope. Successively divide the number by 10 and work with the modulus.
    – Reinderien
    9 hours ago










  • Ok, I will try that out. However, I was wondering what would be the cons of converting it to a list/str?
    – HackersInside
    9 hours ago










  • It's slower and uses (slightly) more memory.
    – Reinderien
    9 hours ago










  • Ok, thanks. I will work on the code
    – HackersInside
    8 hours ago


















  • How am I supposed to iterate over a number, even if I break the number to digits, I will have to store it in a list for further processing.
    – HackersInside
    9 hours ago










  • Nope. Successively divide the number by 10 and work with the modulus.
    – Reinderien
    9 hours ago










  • Ok, I will try that out. However, I was wondering what would be the cons of converting it to a list/str?
    – HackersInside
    9 hours ago










  • It's slower and uses (slightly) more memory.
    – Reinderien
    9 hours ago










  • Ok, thanks. I will work on the code
    – HackersInside
    8 hours ago
















How am I supposed to iterate over a number, even if I break the number to digits, I will have to store it in a list for further processing.
– HackersInside
9 hours ago




How am I supposed to iterate over a number, even if I break the number to digits, I will have to store it in a list for further processing.
– HackersInside
9 hours ago












Nope. Successively divide the number by 10 and work with the modulus.
– Reinderien
9 hours ago




Nope. Successively divide the number by 10 and work with the modulus.
– Reinderien
9 hours ago












Ok, I will try that out. However, I was wondering what would be the cons of converting it to a list/str?
– HackersInside
9 hours ago




Ok, I will try that out. However, I was wondering what would be the cons of converting it to a list/str?
– HackersInside
9 hours ago












It's slower and uses (slightly) more memory.
– Reinderien
9 hours ago




It's slower and uses (slightly) more memory.
– Reinderien
9 hours ago












Ok, thanks. I will work on the code
– HackersInside
8 hours ago




Ok, thanks. I will work on the code
– HackersInside
8 hours ago










HackersInside is a new contributor. Be nice, and check out our Code of Conduct.










draft saved

draft discarded


















HackersInside is a new contributor. Be nice, and check out our Code of Conduct.













HackersInside is a new contributor. Be nice, and check out our Code of Conduct.












HackersInside is a new contributor. Be nice, and check out our Code of Conduct.
















Thanks for contributing an answer to Code Review Stack Exchange!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


Use MathJax to format equations. MathJax reference.


To learn more, see our tips on writing great answers.





Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


Please pay close attention to the following guidance:


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f209680%2fimplementation-of-luhn-credit-card-algorithm%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

Mont Emei

Province de Neuquén

Journaliste