From: dblack@... Date: 2002-10-15T11:00:21+09:00 Subject: Re: Please check my algorithm Hi -- On Tue, 15 Oct 2002, Vincent Foley wrote: > Hi, I found a nice programming challenge: > http://acm.uva.es/p/v3/333.html That is quite a cool one. > I have written an entry in Ruby, and I'd like to know if there are > things I could improve. > > #!/usr/bin/env ruby > > class ISBN > def initialize(code) > @code = code > end > > def calc(lst) > ans = [] > ans[0] = lst[0] > for i in 1...lst.length > ans[i] = ans[i-1] + lst[i] > end > ans > end This struck me as a good candidate for the new #inject method, though that's only in 1.7. (See below.) > def validChars > stripCode = @code.tr("-", "") > if stripCode =~ /^[0-9]{9}[0-9X]$/i > true > else > false > end > end Unless you really need 'true' and 'false', you could just do: def valid_chars /^\d{9}[\dX]$/i.match(@code.delete("-")) end and let the MatchData/nil distinction serve for the Boolean test. (OK, I admit I'm slipping in some subliminal antiCamelCase propaganda :-) > > def validate > if validChars then > stripCode = @code.tr("-", "") You've got that twice; you might want to have a separate method, or instance variable, for the tr'd version. > [...] Well, for what it's worth, here's my 1.7-only version (it uses #inject). I can't help feeling there's a way to do some kind of double inject, and avoid using the 't' accumulator... but anyway, here is its current incarnation: #!/usr/local/lib/ruby/1.7/bin/ruby -w class ISBN < String ISBN_RE = /^\s*(\d-?){9}(X|\d)\s*$/ def check t = 0 ISBN_RE.match(self) && numbers.inject(0) {|x,y| t += x+y; x+y } && (t % 11) .zero? end def numbers strip.delete('-').split(//).map {|i| i.sub(/X/,"10").to_i} end end p ISBN.new("0-89237-010-6").check # true p ISBN.new("0-89237-010-5").check # false p ISBN.new("blah").check # nil __END__ (The nil/false thing could be smoothed out if necessary.) David -- David Alan Black home: dblack@candle.superlink.net work: blackdav@shu.edu Web: http://pirate.shu.edu/~blackdav