-
Notifications
You must be signed in to change notification settings - Fork 544
Implement Luhn #247
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement Luhn #247
Conversation
Closes exercism#237 This mostly follows the current test suite (exercism/problem-specifications#491), with one change. The final canonical test adds an alphabetical character to a known invalid string and then asserts that it's still invalid. Instead what the test should do is alter a known-valid string and show that it is now invalid. That's what I've done here. I'll also propose the change to canonical test suite.
} | ||
|
||
candidate.chars() | ||
.filter(|c| c.is_numeric()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can I suggest filter_map
here? It seems perfect for this use.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yep.
Thinking about placement. I don't think my solution is that far from what people will do. The existing crate uses another crate to handle digits > 10 after doubling. If people go down that path their solutions will vary a bit from mine, but not by a bunch. So the solution mostly requires a good handle on
I would put it between Sum of Multiples and Scrabble Score. Update: The conversion of a string to digits is also part of Largest Series Product, so we could move the exercise to right before LSP to reinforce that concept. |
I don't think my solution is that far from what people will do. The [existing crate](https://lunemec.github.io/rust-luhn/src/luhn2/src/lib.rs.html) uses another crate to handle digits > 10 after doubling. If people go down that path their solutions will vary a bit from mine, but not by a bunch. So the solution mostly requires a good handle on - Converting a string to digits - Working with iteration The conversion of a string to digits is also part of Largest Series Product, so we could put the exercise to right before LSP to reinforce that concept.
9581ad7
to
00715b5
Compare
While implementing these tests for Rust I found that the final test was not well written (my fault!) exercism/rust#247 I added the alphabetical character to an already-invalid string. So the test doesn't show anything useful. Instead the test should show that a known-valid string is made invalid by the inclusion of a non-digit
This works, but I've been thinking about some other, more Rusty ways of approaching it. Option 1: Use
|
Option 3Do all of them. Have 3 Luhn exercises that show different ways of solving the problem, so that students can see each approach. |
I know you already placed, but I'm going to make my placement comment without looking at where you placed to avoid bias, and if our ideas match up then great. Place no later than robot-simulator. Fantastic, we agree. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we could validate strings and different types of unsized ints
A bit of a shame that strings with leading zeroes lose their leading zeroes, but fortunately this doesn't affect correcntess.
Students would create a LuhnValidator trait and then implement it for different types.
Yeah, interesting way to add functions to existing types. Do we have any exercise that already does this? I think it's a good thing to show off at some point.
Looking at our git grep "impl.*for"
, I guess not.
Hmm, https://doc.rust-lang.org/book/traits.html#rules-for-implementing-traits says "It is considered poor style to implement methods on such primitive types, even though it is possible.", I wonder if we should still show it anyway.
.rev() | ||
.enumerate() | ||
.map(|(index, digit)| if index % 2 == 0 { digit } else { digit * 2 }) | ||
.map(|digit| if digit > 10 { digit - 9 } else { digit }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sorry, but this code says !is_valid("59")
and is_valid("50")
, when instead it should say is_valid("59")
and !is_valid("50")
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, good catch. Should be digit > 9
.
|
||
#[test] | ||
#[ignore] | ||
fn valid_canadian_sin_is_valid() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
long cat is long.
(No change necessary)
Just this week I was trying to figure out how to monkey-patch Ruby to add methods to the number I'm going to experiment with Option 3 and will either update this PR or create a new one. |
* Luhn: Update test of non-digit While implementing these tests for Rust I found that the final test was not well written (my fault!) exercism/rust#247 I added the alphabetical character to an already-invalid string. So the test doesn't show anything useful. Instead the test should show that a known-valid string is made invalid by the inclusion of a non-digit
This is an implementation of the idea I discussed here exercism#247 (comment) After students do the original Luhn exercise, they can learn how to use the From trait to allow validation of multiple types. I've put this right after Luhn, which might be a bit early for introducing Traits.
This implements the Trait-based API that I proposed here exercism#247 (comment) As pointed out by Peter, using traits like this is probably an anti-pattern. I'm somewhat on the fence about demonstrating it.
This is an implementation of the idea I discussed here exercism#247 (comment) After students do the original Luhn exercise, they can learn how to use the From trait to allow validation of multiple types. I've put this right after Luhn, which might be a bit early for introducing Traits.
This implements the Trait-based API that I proposed here exercism#247 (comment) As pointed out by Peter, using traits like this is probably an anti-pattern. I'm somewhat on the fence about demonstrating it.
This implements the idea I discussed here exercism#247 (comment) After students do the original Luhn exercise, they can now do "Luhn: Using the From Trait" to allow validation of multiple types. And after that, they can do "Luhn: Using a Custom Trait" to develop their own trait.
This implements the idea I discussed here exercism#247 (comment) After students do the original Luhn exercise, they can now do "Luhn: Using the From Trait" to allow validation of multiple types. And after that, they can do "Luhn: Using a Custom Trait" to develop their own trait. "Luhn: Using the From Trait" is placed just after Bracket Push (which also uses `From`). In the Luhn implementation students will implement `From` for multiple types, so it makes sense to put it after Bracket Push where students only implement it for one type. "Luhn: Using a Custom Trait" moves to after Space Age. Space Age solutions use custom traits and `From`, so pairing these exercises made sense.
Closes #237
This mostly follows the current test suite
(exercism/problem-specifications#491), with one change.
The final canonical test adds an alphabetical character to a known
invalid string and then asserts that it's still invalid.
Instead what the test should do is alter a known-valid string and show
that it is now invalid.
That's what I've done here. I'll also propose the change to canonical
test suite.