From: Morton Goldberg Date: 2007-08-06T00:56:07+09:00 Subject: Re: [QUIZ] Numbers Can Be Words (#133) [SOLUTION] Here are some solutions to this quiz. The first solution deliberately avoids using regular expressions. Note the use of next to skip over words that are too short or capitalized and break to stop the iteration when it gets into territory beyond where numbers of the given base exist. WORD_LIST = "/usr/share/dict/words" WORDS = File.read(WORD_LIST).split def number_words(base=16, min_letters=3) result = [] WORDS.each do |w| next if w.size < min_letters || (?A..?Z).include?(w[0]) break if w[0] > ?a + (base - 11) result << w if w.to_i(base).to_s(base) == w end result end number_words(18, 5) # => ["abaca", "abaff", "accede", "achage", "adage", "added", "adead", "aface", "ahead", "bacaba", "bacach", "bacca", "baccae", "bache", "badge", "baggage", "bagged", "beach", "beached", "beachhead", "beaded", "bebed", "bedad", "bedded", "bedead", "bedeaf", "beech", "beedged", "beefhead", "beefheaded", "beehead", "beeheaded", "begad", "behead", "behedge", "cabbage", "cabbagehead", "cabda", "cache", "cadge", "caeca", "caffa", "caged", "chafe", "chaff", "chebec", "cheecha", "dabba", "dagaba", "dagga", "dahabeah", "deadhead", "debadge", "decad", "decade", "deedeed", "deface", "degged", "dhabb", "echea", "edged", "efface", "egghead", "facade", "faced", "faded", "fadge", "feedhead", "gabgab", "gadbee", "gadded", "gadge", "gaffe", "gagee", "geggee", "hache", "haggada", "hagged", "headache", "headed", "hedge"] The second solution uses #inject rather than #each, but doesn't seem to be much if any of an improvement. I found it interesting because it's one of few times I've ever needed to pass an argument to break and next. WORD_LIST = "/usr/share/dict/words" WORDS = File.read(WORD_LIST).split def number_words(base=16, min_letters=3) WORDS.inject([]) do |result, w| next result if w.size < min_letters || (?A..?Z).include?(w[0]) break result if w[0] > ?a + (base - 11) result << w if w.to_i(base).to_s(base) == w result end end number_words(20, 7) # => ["accidia", "accidie", "acidific", "babiche", "bacchiac", "bacchic", "bacchii", "badiaga", "baggage", "beached", "beachhead", "beedged", "beefhead", "beefheaded", "beehead", "beeheaded", "behedge", "bighead", "cabbage", "cabbagehead", "caddice", "caddiced", "caffeic", "cheecha", "cicadid", "dahabeah", "deadhead", "debadge", "debeige", "decadic", "decafid", "decided", "deedeed", "deicide", "diffide", "edifice", "egghead", "feedhead", "giffgaff", "haggada", "haggadic", "headache", "jibhead"] In my third and last solution, I take the obvious route and use regular expressions. Maybe regular expressions are better after all. WORD_LIST = "/usr/share/dict/words" WORDS = File.read(WORD_LIST).split def number_words(base=16, min_letters=3) biggest_digit = (?a + (base - 11)) regex = /\A[a-#{biggest_digit.chr}]+\z/ result = [] WORDS.each do |w| next if w.size < min_letters || w =~ /^[A-Z]/ break if w[0] > biggest_digit result << w if w =~ regex end result end The following are all the hex numbers in word list which have at least three letters. number_words # => ["aba", "abac", "abaca", "abaff", "abb", "abed", "acca", "accede", "ace", "adad", "add", "adda", "added", "ade", "adead", "aface", "affa", "baa", "baba", "babe", "bac", "bacaba", "bacca", "baccae", "bad", "bade", "bae", "baff", "bead", "beaded", "bebed", "bed", "bedad", "bedded", "bedead", "bedeaf", "bee", "beef", "cab", "caba", "cabda", "cad", "cade", "caeca", "caffa", "cede", "cee", "dab", "dabb", "dabba", "dace", "dad", "dada", "dade", "dae", "daff", "dead", "deaf", "deb", "decad", "decade", "dee", "deed", "deedeed", "deface", "ebb", "ecad", "edea", "efface", "facade", "face", "faced", "fad", "fade", "faded", "fae", "faff", "fed", "fee", "feed"] Regards, Morton