Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Change all array elements which include a specific string

array = ["Spam is bad", "Ham is good"]

I would like select the element(s) from the array which include(s) the word 'good' and set the string to a new variable. How could I do this?

like image 432
Dru Avatar asked Dec 03 '11 13:12

Dru


4 Answers

Since neither answer so far instructs you on how to update the string in the array to the new value, here are some options:

# Find every string matching a criteria and change them
array.select{ |s| s.include? "good" }.each{ |s| s.replace( "bad" ) }

# Find every string matching a pattern and change them
array.grep.replace( "bad" ).each{ |s| s.replace( "bad" ) }

# Find the first string matching a criteria and change it
array.find{ |s| s =~ /good/ }.replace( "bad" )

However, all of the above will change every instance of a string. For example:

jon   = Person.new "Johnny B. Goode"
array = [ jon.name, "cat" ]
array.find{ |s| s =~ /good/i }.replace( "bad" )

p array #=> "bad"
p jon   #=> #<Person name="bad">  Uh oh...

If you don't want this side effect—if you want to replace the string in the array with a different string, but not change the string itself–then you need to find the index of the item and update that:

# Find the _first_ index matching some criteria and change it
array[ array.index{ |s| s =~ /good/ } ] = "bad"

# Update _every_ item in the array matching some criteria    
array[i] = "bad" while i = array.index{ |s| s =~ /good/i }

# Another way to do the above
# Possibly more efficient for very large arrays any many items
indices = array.map.with_index{ |s,i| s =~ /good/ ? i : nil }.compact
indices.each{ |i| array[i] = "bad" }

Finally, the simplest and mostly fastest, without mucking about with indices:

# Create a new array with the new values
new_array = array.map do |s|
  if s =~ /good/i  # matches "Good" or "good" in the string
    "bad"
  else
    s
  end
end

# Same thing, but shorter syntax
new_array = array.map{ |s| s =~ /good/i ? "bad" : s }

# Or, change the array in place to the new values
new_array = array.map!{ |s| s =~ /good/i ? "bad" : s }
like image 76
Phrogz Avatar answered Oct 24 '22 08:10

Phrogz


map! sounds like a good choice.

x = ['i', 'am', 'good']
def change_string_to_your_liking s
    # or whatever it is you plan to do with s
    s.gsub('good', 'excellente!')
end
x.map! {|i| i =~ /good/ ?  change_string_to_your_liking(i) : i}
puts x.inspect
like image 24
kikuchiyo Avatar answered Oct 24 '22 10:10

kikuchiyo


There's also a special method for this:

array.grep(/good/)  # => ["Ham is good"]

With #grep you can do a lot because it takes a regular expression...

like image 2
Marek Příhoda Avatar answered Oct 24 '22 08:10

Marek Příhoda


It's almost as you typed your title:

array.select {|s| s.include? "good"}

Here's the doc: http://www.ruby-doc.org/core-1.9.3/Array.html#method-i-select

like image 1
deviousdodo Avatar answered Oct 24 '22 09:10

deviousdodo