fREWdiculous!
15 May
My coworker Wes asked me if there could be a nice refactor for the following function which checks CAS Numbers to ensure their validity. After struggling for 30 minutes I gave up trying to make it a little bit nicer with reduce.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
Let’s take a look at this and figure it out. The crunchy bit is the for loop, so I’ll go through that. Basically we are summing each item times a weight that is inversely proportional to it’s location in the list. Or to be more explicit, let’s do an example on the board (7732-18-5.) 5 is the check digit.
| $_ | $count | $_ * $count | $sum |
|---|---|---|---|
| 7 | 6 | 42 | 42 |
| 7 | 5 | 35 | 77 |
| 3 | 4 | 12 | 89 |
| 2 | 3 | 6 | 95 |
| 1 | 2 | 2 | 97 |
| 8 | 1 | 8 | 105 |
So basically we are making a special summation. The thing that’s unusual is that we have a decrementing counter along with it. If I had the control structure which I am about to show you in my mind already the solution might have jumped out sooner.
So I asked about it in #perl6 and it turns out there is a very nice Perl 6 version. It takes advantage of the mystical hyperoperator (>>infix op<<); that is, it takes two lists and performs an operation on each element together. Think SIMD. It also uses reduce ([infix op]) which I have mentioned before. Check it out!
1 2 3 4 5 6 7 8 9 10 | sub cas(Str $cas) { if $cas ~~ /(\d ** 1..8)\-(\d\d)\-(\d)/ { my @digits = $0~$1.split ''; my $check = $2; return ([+] @digits.reverse >>*<< (1..@digits)) % 10 == $check; } return Bool::False; } |
This does the same thing as above. Or to put it in English, we take our digits, reverse them, and then multiply each digit (hyperoperator, >>*<<) by the respective integer in the other list, that is, 1 to the size of the list. We then sum (reduce, [+]) that new list, and get the modulus 10 of it.
Very elegant, no?
Update: Turns out there is also a very elegant version in p5, according to mst. Check it out!
1 2 3 4 5 6 7 8 9 10 11 12 |
It’s very similar to the p6 version, just using fewer generalized operators, so you should be able to follow it fairly well.
Leave a reply