It’s been a while since I last wrote something in the blog. The culprit? My MBA dissertation research study. A small advice from the newly found wisdom: If someone ever suggests you should do a nationwide survey of any kind, respectfully decline unless you live in Vatican or Monaco, or unless someone pays you to do it :). Doing it for the sake of an MBA research, even for the dissertation, is a huge pain; just choose a theoretical subject and bury yourself in books, it beats dealing with telephone interviews with paranoid members of the population, then having to trust their half-witted answers for a serious subject such as electronic retailing. Well, I did not procrastinate (my old favorite word) and I persevered (my new favorite word) and completed my research with great results, leaving me with more time to play. So, the question now is how best to celebrate the return to blogosphere? Maybe a nice one-liner LINQ to validate LUHN check?
I’ve been designing a credit card processing framework to consolidate my client’s multiple billing systems over a single audited billing system and one thing that every credit card processing piece of code has is Luhn check. As I was about to copy/paste it from my age old “library of ill conceived and poorly organized snippets”™ I said to myself: lets make this interesting. Lets make it in Linq, but not just any Linq, I wanted to make it as comparable to bare-metal code as possible with as little temporary waste. To my surprise, the vast library of dissipating knowledge also known as the cloud (or Internet, as we old people call it) yielded no results aside from a single example that didn’t even work; I don’t do finger pointing, but if you recognized yourself as the author of a Linq Luhn code currently on the net do note that you can’t just multiply numbers by 2 and sum them up as whole numbers, you have to sum the individual digits or do a –9 trick, also SelectMany is not needed here and slows things down, there is no drill down here.
Iteration after iteration and with some help (see below), I present you the final version (so far) doing the quick’n’dirty Luhn check, I broke it down to multiline to make it more readable, but in effect it is a one-liner:
- using System;
- using System.Linq;
-
-
- public bool CheckLUHN(string cardNumber)
- {
- return cardNumber
- .Reverse()
- .Select((c, i) => (c - 48) << (i & 1))
- .Select(s => s > 9 ? s - 9 : s)
- .Sum()%10 == 0;
- }
What makes it quick’n’dirty is that it assumes that cardNumber is all digits; if this bugs you really hard just add .Where(c => Char.IsDigit(c)) before .Reverse(). Anyway, the method creates no temporary storage other then internal position state of the three IEnumerable iterators used, ultimately the Sum() picks its data from the cardNumber string and does so in a single loop with three yields per cycle. Looking at the library and other solutions offered elsewhere this one seems just as good. What we do is create three IEnumerable iterators, the first enumerates the string by characters in the reverses order, the second one converts them to digits and multiples even-positioned ones, the last one just trims two-digit numbers to a one-digit partial sum. I hope I don’t have to explain what Sum() does in the end and why we mod 10 the sum.
Special thanks to Igor Gajić from Vega IT Sourcing for bringing Func<TSource, int, TResult> selector form to my attention. The biggest problem I had was determining digits’ index position in order to determine which ones to multiply and I even stooped to using an aggregation over an anonymous type to achieve flip-flopping, all that time this form just gave it on a platter with zero hassle. It even says so in the MSDN library for those who can read it :) Who reads MSDN anyway?