patternrubyMinor
Ruby implementation of Soundex algorithm
Viewed 0 times
implementationalgorithmsoundexruby
Problem
I'm new to Ruby. I normally sling code in C#. What could I do to make this simple Soundex class more Rubyesque?
The output is:
Smith => S530
Johnson => J525
Williams => W452
Jones => J520
Brown => B650
class Surname
attr_accessor :value
def initialize(input)
@value = input
end
def soundex
result = ''
@value.chars.drop(1).each do |s|
number = soundex_value(s).to_s
result << number unless result[-1,1] == number
end
@value.chars.first << result.ljust(3,'0')
end
def soundex_value(s)
case s
when /[bfpv]/
1
when /[cgjkqsxz]/
2
when /[dt]/
3
when /l/
4
when /[mn]/
5
when /r/
6
else ''
end
end
end
def print_name(input)
surname = Surname.new(input)
puts(surname.value + ' => ' + surname.soundex)
end
['Smith', 'Johnson', 'Williams', 'Jones', 'Brown'].each do |s|
print_name s
endThe output is:
Smith => S530
Johnson => J525
Williams => W452
Jones => J520
Brown => B650
Solution
Per your request, your code converted to the Ruby way perhaps would be as follows.
A small point: in our output, in the Ruby world, we would avoid the => fat comma which Rubyists (at least in the English-speaking world) call a 'hash-rocket' because:
BTW, we also would avoid ->, dash-greater-than, which in Ruby (syntax) generates a lambda.
gives the results
Smith: S530
Johnson: J525
Williams: W452
Jones: J520
Brown: B650
Atchison: A325
A small point: in our output, in the Ruby world, we would avoid the => fat comma which Rubyists (at least in the English-speaking world) call a 'hash-rocket' because:
- It reads like Ruby's (older) hash accessing syntax.
- In Ruby language documentation (e.g., see Array), the similar #=>, comprising a hash to introduce a comment, followed by a hash-rocket (presumably, this gave us the name), shows us the result (or value) of an individual line of code—the two meanings conflict.
BTW, we also would avoid ->, dash-greater-than, which in Ruby (syntax) generates a lambda.
class Soundex < String
IGNORED_BEGINNING_LENGTH = 1
MINIMUM_LENGTH = 3
CASES = [ # Keep order.
/[bfpv]/,
/[cgjkqsxz]/,
/[dt]/,
/l/,
/[mn]/,
/r/,
]
CASES_LENGTH = CASES.length
def initialize(surname)
a = surname.split ''
kept = a.take(IGNORED_BEGINNING_LENGTH).join ''
indices = a.drop(IGNORED_BEGINNING_LENGTH).map do |e|
(0...CASES_LENGTH).detect{|i| e =~ (CASES.at i)}
end.compact
# Adjust to one-based notation; collapse repetition; right-pad with zeros.
digits = indices.map(&:succ).join('').squeeze.ljust MINIMUM_LENGTH, '0'
super kept + digits
end
def self.show(s) "#{s}: #{new s}" end
end
names = %w[Smith Johnson Williams Jones Brown Atchison]
names.each{|s| puts Soundex.show s}gives the results
Smith: S530
Johnson: J525
Williams: W452
Jones: J520
Brown: B650
Atchison: A325
Code Snippets
class Soundex < String
IGNORED_BEGINNING_LENGTH = 1
MINIMUM_LENGTH = 3
CASES = [ # Keep order.
/[bfpv]/,
/[cgjkqsxz]/,
/[dt]/,
/l/,
/[mn]/,
/r/,
]
CASES_LENGTH = CASES.length
def initialize(surname)
a = surname.split ''
kept = a.take(IGNORED_BEGINNING_LENGTH).join ''
indices = a.drop(IGNORED_BEGINNING_LENGTH).map do |e|
(0...CASES_LENGTH).detect{|i| e =~ (CASES.at i)}
end.compact
# Adjust to one-based notation; collapse repetition; right-pad with zeros.
digits = indices.map(&:succ).join('').squeeze.ljust MINIMUM_LENGTH, '0'
super kept + digits
end
def self.show(s) "#{s}: #{new s}" end
end
names = %w[Smith Johnson Williams Jones Brown Atchison]
names.each{|s| puts Soundex.show s}Context
StackExchange Code Review Q#5689, answer score: 3
Revisions (0)
No revisions yet.