4

I'm trying to iterate through an array of strings and replace the words if they match any of the substitution rules:

array= ["I love chicken!", "I love lamb!", "I love beef!"]
substitutions = {
"love" => "hate",
"lamb" => "turkey"
}

I want to iterate through the array and check for any words that match with the keys within the substitutions hash. The array would then become:

array= ["I hate chicken!", "I hate turkey!", "I hate beef!"]

This is what I have so far:

array.each do |strings|
strings = strings.split
    strings.each do |word|
        substitutions.each do |phrase,substitute|
            if word == phrase
                word = substitute
                return word
            end
        end
    end
end
the Tin Man
  • 158,662
  • 42
  • 215
  • 303
Jun Huang
  • 85
  • 7

3 Answers3

2

This will give you the result you need. As you may see, you are overcomplicating a bit

arry= ["I love chicken!", "I love lamb!", "I love beef!"]
substitutions = { "love" => "hate", "lamb" => "turkey" }

arry.each_with_index do |str,ind|
  substitutions.each_key do |word|
    arry[ind].gsub!(word,substitutions[word]) if str.include?(word)
  end
end

puts arry

This will give you:

[ "I hate chicken!", "I hate turkey!", "I hate beef!" ]

Your strategy of spliting the sentences wouldn't work. The exclamation marks would create some trouble. The idea of testing with #include? is much better in this case.

And notice the use of gsub! (with the !), which will make the changes in the original array.

Ed de Almeida
  • 3,675
  • 4
  • 25
  • 57
  • 1
    No need to define the keys-array `words`. Iterate over the `substitutions` hash with [Hash#each_key](http://ruby-doc.org/core-2.3.3/Hash.html#method-i-each_key) – Sagar Pandya Dec 09 '16 at 00:02
1
arr  = ["I love chicken!", "I love lamb!", "I love beef!"]
subs = { "love"=>"hate", "lamb"=>"turkey" }

subs.default_proc = ->(h,k) { k }
  #=> #<Proc:0x007f9ff0a014b8@(irb):1343 (lambda)>
arr.map { |s| s.gsub(/\w+/, subs) }
  #=> ["I hate chicken!", "I hate turkey!", "I hate beef!"]

I used Hash#default_proc= to attach a proc to subs so that subs[k] returns k if subs does not have a key k and used the form of String#gsub that employs a hash for making substitutions.

Cary Swoveland
  • 106,649
  • 6
  • 63
  • 100
0

It's not necessary to iterate over the hash at all. Instead use it to generate a regular expression and pass it to gsub. Here's how I've done it many times; It's the basis for a templating engine:

array = ["I love chicken!", "I love lamb!", "I love beef!"]
substitutions = {
  "love" => "hate",
  "lamb" => "turkey"
}

key_regex = /\b(?:#{Regexp.union(substitutions.keys).source})\b/
# => /\b(?:love|lamb)\b/

array.map! { |s|
  s.gsub(key_regex, substitutions)
}

array # => ["I hate chicken!", "I hate turkey!", "I hate beef!"]

If you don't want to munge the contents of array use map instead, which will return a new array leaving the original untouched:

array.map { |s|
  s.gsub(key_regex, substitutions)
}
# => ["I hate chicken!", "I hate turkey!", "I hate beef!"]

array # => ["I love chicken!", "I love lamb!", "I love beef!"]

The trick is defining the regular expression used to find the key words.

See "How to build a case-insensitive regular expression with Regexp.union" along with the gsub documenation for more information.

Community
  • 1
  • 1
the Tin Man
  • 158,662
  • 42
  • 215
  • 303