1

I have a hash like this:

test
 => {"QTC-1 test"=>"pass", "QTC-2 test"=>"fail"}

I want to take each key in the hash and remove all characters after the numbers, example:

"QTC-1 test" should equal "QTC-1"

I am close to the solution but not fully there:

str = test.keys[0]
 => "QTC-1 test" 

new = str.slice(0..(str.index(/\d/)))
 => "QTC-1" 

But need some help doing that with the hash key(s).

Bonus

Changing the values to corresponding number values:

So if value = pass then change it to 1 or if value = fail then change it to 2.

Bonus possible answer:

scenarios.each_pair { |k, v| 

  case v
  when 'pass'
    scenarios[k] = 1
  when 'fail'
    scenarios[k] = 2
  when 'block'
    scenarios[k] = 3
  else
    scenarios[k] = 4
  end

  }
Farooq
  • 1,925
  • 3
  • 15
  • 36
  • You can't change the keys, but you can insert the same values under new keys (and delete old keys) or create a brand new hash with correct keys. – Sergio Tulentsev Aug 19 '14 at 15:20

6 Answers6

4
h = {"QTC-1 test"=>"pass", "QTC-2 test"=>"fail"}

use hash#transform_keys. It will make the change only to keys

new_hash = h.transform_keys {|k| k.sub /\stest\z/, '' }

and return a new has. Otherwise use transform_keys! (with the bang).

Ruby Doc: https://ruby-doc.org/core-2.7.2/Hash.html#method-i-transform_keys-21 .

Felix
  • 4,510
  • 2
  • 31
  • 46
Dhanabal
  • 121
  • 1
  • 7
3

With Ruby 2.1.2:

test = {"QTC-1 test"=>"pass", "QTC-2 test"=>"fail"}
(test.keys.map { |k| k.sub /\stest\z/, '' }.zip test.values).to_h 
#=> {"QTC-1"=>"pass", "QTC-2"=>"fail"}

The idea here is that you strip the string " test" from each key, zip it together with the values from your original hash, and then turn the resulting array back into a hash.

Todd A. Jacobs
  • 81,402
  • 15
  • 141
  • 199
3

This answer modifies the original hash rather than creating a new one.

h = {"QTC-1 test"=>"pass", "QTC-2 test"=>"fail"}
h.keys.each{|k| h[k[/.*\d+/]] = h.delete(k)}
h #=> {"QTC-1"=>"pass", "QTC-2"=>"fail"}
sawa
  • 165,429
  • 45
  • 277
  • 381
1
new_hash = {}
old_hash = {"QTC-1 test"=>"pass", "QTC-2 test"=>"fail"}
old_hash.map{|key, value| new_hash[key.split(" ").first]=value}

p new_hash
usha
  • 28,973
  • 5
  • 72
  • 93
1
h = {"QTC-1 test"=>"pass", "QTC-2 test"=>"fail"}
Hash[h.map { |k,v| [k.sub(/(?<=\d).*/, ''), v] }]
# => {"QTC-1"=>"pass", "QTC-2"=>"fail"}
falsetru
  • 357,413
  • 63
  • 732
  • 636
1

For the bonus portion:

To update from "pass" or "fail" to number values on your newly-revised hash, you could use #each_pair with a conditional. The ternary operator format is used here:

test = {"QTC-1 test"=>"pass", "QTC-2 test"=>"fail"}
test.each_pair { |k, v| v == "pass" ? test[k] = 1 : test[k] = 2 }
# => {"QTC-1 test"=>1, "QTC-2 test"=>2}

Update for situation where there are more options than "pass" and "fail"... You can use a case statement:

test = 
  {
    "QTC-1 test" => "pass",
    "QTC-2 test" => "fail",
    "QTC-3 test" => "blocked",
    "QTC-4 test" => "denied",
    "QTC-5 test" => "other",
    "QTC-6 test" => "error"
  }

test.each_pair do |k, v|
  case v
  when "pass"
    test[k] = 1
  when "fail"
    test[k] = 2
  when "blocked"
    test[k] = 3
  when "denied"
    test[k] = 4
  when "other"
    test[k] = 5
  else
    test[k] = "well dangit, I don't know what to do with #{v}"
  end
end

p test

=> {"QTC-1 test"=>1, 
    "QTC-2 test"=>2, 
    "QTC-3 test"=>3, 
    "QTC-4 test"=>4, 
    "QTC-5 test"=>5, 
    "QTC-6 test"=>"well dangit, I don't know what to do with error"}
Community
  • 1
  • 1
Dan Wagner
  • 2,693
  • 2
  • 13
  • 18
  • Thanks Dan, what if I have more than 2 options? Like: 1 = pass, 2 = fail, 3 = blocked, etc. – Farooq Aug 19 '14 at 15:40
  • I'm thinking something like this might work: scenarios.each_pair { |k, v| case v when 'pass' scenarios[k] = 1 when 'fail' scenarios[k] = 2 when 'block' scenarios[k] = 3 else scenarios[k] = 4 end } Edited first post for easier readibility. – Farooq Aug 19 '14 at 15:48
  • 1
    Yep @Farooq you nailed it, I think a `case` statement is a good technique here – Dan Wagner Aug 19 '14 at 15:52