Reputation: 6907
I have a Ruby string, for instance: "blue green yellow dog cat mouse alpha beta"
.
I want to replace:
"color"
,"animal"
, and"letter"
.In other words, in my example above, I would like the new string to be:
"color animal letter"
and not
"color color color animal animal animal letter letter"
I came up with the following method:
def convert_string(string)
if ["cat", "dog", "mouse"].include? key.to_s
return "animal"
end
if ["blue", "yellow", "green"].include? key.to_s
return "color"
end
if ["alpha", "beta"].include? key.to_s
return "letter"
end
return key
end
How can I improve my method to achieve what I need?
Upvotes: 1
Views: 285
Reputation: 110755
Suppose:
str = "gamma blue green yellow dog cat mouse alpha beta"
Notice that str
is slightly different than the example given in the question.
I've assumed that you want to replace each run of colors (or animals or letters) in the string by the word "color" (or "animals" or "letters").
Here are two ways to do that.
#1
This uses Enumerable#chunk and Object#itself. The latter was introduced in v.2.2. For earlier versions, write ...chunk { |s| s }...
.
str.split.map do |word|
case word
when "blue", "green", "yellow"
"color"
when "dog", "cat", "mouse"
"animal"
when "alpha", "beta", "gamma"
"letter"
end
end.chunk(&:itself).map(&:first).join(' ')
#=> "letter color animal letter"
map
returns:
#=> ["letter", "color", "color", "color", "animal",
# "animal", "animal", "letter", "letter"]
which is then chunk
ed. Denoting this array as arr
, an alternative to chunking is:
arr.each_with_object([]) { |w,a| a << w if a.empty? || w != a.last }
#2
COLOR = "color"
ANIMAL = "animal"
LETTER = "letter"
h = { COLOR => %w{ blue green yellow },
ANIMAL => %w{ dog cat mouse },
LETTER => %w{ alpha beta gamma } }.
each_with_object({}) { |(k,v), h| v.each { |item| h[item] = k } }
#=> {"blue"=>"color", "green"=>"color", "yellow"=>"color",
# "dog"=>"animal", "cat"=>"animal", "mouse"=>"animal",
# "alpha"=>"letter", "beta"=>"letter", "gamma"=>"letter"}
r = /
\b # match a word break
(\w+) # match a word in capture group 1
(?:\s\1)+ # match one or more copies of the matched word, each preceded by a space
\b # match a word break
/x # extended or free-spacing mode
str.gsub(/\w+/,h).gsub(r,'\1')
#=> "letter color animal letter"
or
str.split.map { |word| h[word] }.chunk(&:itself).map(&:first).join(' ')
#=> "letter color animal letter"
Upvotes: 2
Reputation: 44611
You can use gsub
:
str = "blue green yellow dog cat mouse alpha beta"
str.gsub(/(cat|dog|mouse)/, 'animal')
.gsub(/(blue|yellow|green)/, 'color')
.gsub(/(alpha|beta)/, 'letter')
.split.uniq.join ' '
Upvotes: 2