Ruby Quiz <james / grayproductions.net> writes: > You have shown me the light and it tells me... Daniel Martin is crazy. I'll > leave it to him to explain his own solution, as punishment for the time it took > me to puzzle it out. I had to print that Array inside of the inject() call > during each iteration to see how it built up the answer. As if you needed further evidence after my third solution to pp Pascal. And the one in my solution is not *so* bad. The really nasty Luhn implementation was what I posted as a follow-up (http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/249669) That algorithm was: def luhn(s) s.scan(/\d/).map{|x|x.to_i}.inject([0,0]){ |(a,b),c|[b+c%9,a+2*c%9]}[0]%10 == s.scan(/9/).size%10 end Now, here's an explanation of the version in my posted solution: First, the code in my solution was this: def luhn(s) s.scan(/\d/).inject([0,0]){|(a,b),c|[b+c.to_i, a+c.to_i*2%9+(c=='9' ? 9 : 0)]}[0]%10 == 0 end The main issue with doing the Luhn algorithm as a straight-forward inject command is that you don't know on each digit whether this digit is one that should be doubled or not. Now, there are a few ways around this: 1) have a "should_double" variable that you initialize to should_double = (s.length % 2 == 0) and then in your block do should_double = !should_double 2) reverse the data, and use something like each_index to get you the index each time, and double when the index is even (most people did this) 3) like choice (1), but reverse the data and initialize should_double to false. I chose a different path: at each stage, compute both possibilities. That is, do an inject loop with two running totals - one in which the number we're dealing with now should be doubled, and one in which it shouldn't. At each stage, swap the two totals. At the end, pick the total that did not involve doubling the last digit. If the Luhn algorithm just involved adding the doubled digits (and didn't involve the added complication of adding their digits), generating both sums would be just: s.scan(/\d/).map{|x|x.to_i}.inject([0,0]){ |(sum2, sum1),x| [sum1 + x, sum2 + 2*x] } Note how I swapped sum1 and sum2 in the process. Then, to take the sum that did not involve doubling the last digit, just do: s.scan(/\d/).map{|x|x.to_i}.inject([0,0]){ |(sum2, sum1),x| [sum1 + x, sum2 + 2*x] }[0] Now, adding digits of numbers together is the well-known process of "casting out nines", and essentially what you're doing with that sum is taking the residue modulo 9. (in other language: "finding the remainder when dividing by 9") That is, adding the digits together turns 2*x into 2*x%9, except that if x is 9 then you get 9, not 0. This makes our sum algorithm into: s.scan(/\d/).map{|x|x.to_i}.inject([0,0]){ |(sum2, sum1),x| [sum1 + x, sum2 + 2*x%9 + (x==9 ? 9 : 0)] }[0] This is almost my luhn method above, except that I used unhelpful one-letter variable names and didn't do the map call, preferring instead to use .to_i in the body of my inject loop. Now, go back and puzzle out the version I mentioned at the top of this email. That version was born out of a desire to avoid the ? : operator, since I tend to find it ugly. -- s=%q( Daniel Martin -- martin / snowplow.org puts "s=%q(#{s})",s.to_a.last ) puts "s=%q(#{s})",s.to_a.last