user3063045
user3063045

Reputation: 2199

How to remove whitespace from a string in a hash

Here's my example:

hash = {"buy"=>"Buy ", "quantity"=>"3 ", "get"=>"Get ", "reward"=>"1 ", "free"=>"Free"}

def stripit(value)
  #value.gsub!('B', 'C')
  value.gsub!('/\s+/', '')
  value
end

newhash = hash.update(hash){|key,value| stripit(value)}
puts newhash.inspect

gsub works on the value -- the first commented replacement works -- but for some reason it is not removing whitespace.

How can I remove whitespaces from a hash value?

Upvotes: 5

Views: 4738

Answers (5)

suman saurabh
suman saurabh

Reputation: 1

You can also use map with a bang operator of you want, like this:

hash.values.map! {|value| value.strip!}

Upvotes: 0

Cary Swoveland
Cary Swoveland

Reputation: 110675

You do not need the line value in stripit if you replace v.gsub!(/\s+/, '') (or just /\s/) with v.gsub(/\s/, ''). That's permitted (and preferred, imo, for better readability and saving a line of code), because Hash#update (aka merge!) is handling the in-place replacement. (Readers: the asker has that line value because String#gsub! returns nil when no change is made.

You may want confirm the hash value is a string before attempting the substitution (unless you are certain that, even in future, there will never be a value that is not a string, but even then, it does no harm to check).

I suggest the following.

hash = {"buy"=>"Buy It ", "quantity"=>"3 ", "get"=>"Get ", "reward"=>"1 ",
        "free"=>"Free", "THE answer"=> 42 }

if hash is not to be mutated:

hash.merge(hash) { |_,v,_| v.is_a?(String) ? v.gsub(/\s/, '') : v }
  #=> {"buy"=>"BuyIt", "quantity"=>"3", "get"=>"Get", "reward"=>"1", "free"=>"Free"} 
hash
  #=> {"buy"=>"Buy It ", "quantity"=>"3 ", "get"=>"Get ", "reward"=>"1 ",
  #    "free"=>"Free", "THE answer"=>42} 

if hash is to be mutated:

hash.update(hash) { |_,v,_| v.is_a?(String) ? v.gsub(/\s/, '') : v }
  #=> {"buy"=>"BuyIt", "quantity"=>"3", "get"=>"Get", "reward"=>"1",   
  #    "free"=>"Free", "THE answer"=>42} 
hash
  #=> {"buy"=>"BuyIt", "quantity"=>"3", "get"=>"Get", "reward"=>"1",
  #    "free"=>"Free", "THE answer"=>42} 

This uses the forms of Hash#merge and Hash#update that employ a block to determine the values of keys that are present in both hashes being merged. Here that is of course all keys. See the docs for details, particularly the meanings of the three block variables. (I've represented two of the three block variables with underscores to indicate they are not used in the block calculation.)

Another way

If hash is not to be mutated:

hash.keys.each_with_object({}) do |k,h|
  v = hash[k]
  h[k] = v.is_a?(String) ? v.gsub(/\s/, '') : v
end
  #=> {"buy"=>"BuyIt", "quantity"=>"3", "get"=>"Get", "reward"=>"1",
  # "free"=>"Free", "THE answer"=>42} 

hash
  #=> {"buy"=>"Buy It ", "quantity"=>"3 ", "get"=>"Get ", "reward"=>"1 ",
  #    "free"=>"Free", "THE answer"=>42} 

If hash is to be mutated:

hash.keys.each do |k|
  v = hash[k]
  hash[k] = v.is_a?(String) ? v.gsub(/\s/, '') : v
end
  #=> ["buy", "quantity", "get", "reward", "free", "THE answer"]
hash
  #=> {"buy"=>"BuyIt", "quantity"=>"3", "get"=>"Get", "reward"=>"1",
  #    "free"=>"Free", "THE answer"=>42} 

Note that in this last case hash is mutated but the block does not return the updated hash.

Upvotes: 0

jdussault
jdussault

Reputation: 427

I think the problem is that you've wrapped your regex in quotation marks, so it's not matching the way you expect!

value.gsub!(/\s+/, '')


(Edit: complete code, copies original question's code but alters the gsub! argument. Tested with ruby 2.3.1)

hash = {"buy"=>"Buy ", "quantity"=>"3 ", "get"=>"Get ", "reward"=>"1 ", "free"=>"Free"}

def stripit(value)
  value.gsub!(/\s+/, '')
  value
end

newhash = hash.update(hash){|key,value| stripit(value)}
puts newhash.inspect

Output:

{"buy"=>"Buy", "quantity"=>"3", "get"=>"Get", "reward"=>"1", "free"=>"Free"}

Upvotes: 5

Eric Duminil
Eric Duminil

Reputation: 54223

If you want to get a new_hash and not modify the original one :

new_hash = hash.map{|k,v| [k,v.gsub(/\s+/,'')]}.to_h

With Rails or ActiveSupport extensions, it becomes even shorter:

hash.transform_values{|v| v.gsub(/\s+/,'')}

NOTE: It removes any whitespace in the values. "Get A " will be converted to "GetA". String#strip would just convert it to "Get A"

Upvotes: 1

Lukas Baliak
Lukas Baliak

Reputation: 2869

You can use each method with strip! to modify hash values.

hash = {"buy"=>"Buy ", "quantity"=>"3 ", "get"=>"Get ", "reward"=>"1 ", "free"=>"Free"}

hash.each_value(&:strip!)

p hash
# => {"buy"=>"Buy", "quantity"=>"3", "get"=>"Get", "reward"=>"1", "free"=>"Free"}

Upvotes: 12

Related Questions