0

In the following code:

If i wanted to get the value of :a ("apple") I would use "hash[:a]". If I wanted to get the key for "apple" (:a) I would use hash.key("apple").

But how can i return a hash value pair?

hash = {:a => "apple", :b => "banana"}

e.g. check if the hash contains :a, and if it does return the following

=> {:a => "apple"}

thanks.

user2864740
  • 60,010
  • 15
  • 145
  • 220
Zach Smith
  • 8,458
  • 13
  • 59
  • 133
  • There is [`Hash#assoc`](http://www.ruby-doc.org/core-1.9.3/Hash.html#method-i-assoc), but I think it skips a proper hash-based lookup. I would be tempted to use: `r = if h.exists?(k) then [k, h[k]] else nil end` (or adjusted to return a Hash). – user2864740 Jan 10 '14 at 04:34
  • You can do this, but shouldn't, as it uses exceptions for flow-control: `{ a: hash.fetch(:a) } rescue nil` – user229044 Jan 10 '14 at 04:38
  • so best to just assign a new hash then? – Zach Smith Jan 10 '14 at 04:39

4 Answers4

1

If you use Rails, you could use the Hash::slice method:

hash.slice(:a)
the Tin Man
  • 158,662
  • 42
  • 215
  • 303
xdazz
  • 158,678
  • 38
  • 247
  • 274
  • 1
    That's not Ruby, that's [ActiveSupport](http://apidock.com/rails/ActiveSupport/CoreExtensions/Hash/Slice) – user229044 Jan 10 '14 at 04:35
0

You could also use Hash.entries. Entries is returned as an array of arrays of each key + value pair, and can be easily converted to a hash using the splat operator.

hash.entries.each do |entry| 
  p Hash[*entry] if entry.include?(:a) 
end
=> {:a=>"apple"}

As suggested by user2864740, Hash#assoc can also be used (if you are using ruby > 1.9):

Hash[*(hash.assoc(:a))]
Sam
  • 884
  • 6
  • 15
  • what is the * before entry for? – Zach Smith Jan 10 '14 at 04:56
  • The * is the splat operator, which is quick idiom for converting arrays to hashes, and vice-versa. For ex: a = *{:a=>"apple",:b=>"banana"} gives => [[:a,"apple"],[:b,"banana"]] and Hash[*a.flatten] gives => {:a=>"apple",:b=>"banana"}. There are many more uses for the splat operator, which might be beyond the scope for this question, but this might be a good read: http://stackoverflow.com/questions/918449/what-does-the-unary-operator-do-in-this-ruby-code/918475#918475 – Sam Jan 10 '14 at 05:09
  • 1
    *Looping* the hash entries (which is `O(n)`) and then `include?` on each one (which will find `{:foo => :a}` as well)? Why use that over: `r = if h.exists?(k) then {k => h[k]} else nil end` (which doesn't loop or look in the values) or even `Hash#assoc` (which won't have the 2nd issue)? – user2864740 Jan 10 '14 at 05:11
  • @user2864740: I don't think there's a .exists? method for hashes. Also, Hash#assoc is only available for ruby 1.9 onwards, so won't work with 1.8.7 (if needed). Otherwise, you are correct that Hash#assoc can be used. I'll update my answer to reflect that – Sam Jan 10 '14 at 05:26
  • @xammy Whoops, `#exists?` is indeed wrong: I meant [`Hash#has_key?`](http://www.ruby-doc.org/core-1.9.3/Hash.html#method-i-has_key-3F). – user2864740 Jan 10 '14 at 05:28
  • One potential issue with `Hash#assoc` is that it doesn't first perform a hash-lookup; it merely uses `==` on all keys in turn until there is a match. – user2864740 Jan 10 '14 at 05:30
0

If I have a hash:

hash = {:a => "apple", :b => "banana"}

And I wanted to extract a particular key/value pair from it, in the form of a sub-hash, I'd do:

_key = :a
Hash[_key, hash[_key]] # => {:a=>"apple"}

And to do it conditionally:

Hash[_key, hash[_key]] if hash.key?(_key)

But, I'm not sure why pass a single-element hash. If I know the key, I can easily grab the value. If I need to pass them both to another method, I'd do it as an array:

[:a, "apple"]
the Tin Man
  • 158,662
  • 42
  • 215
  • 303
0

Try: Hash#select

hash = {:a => "apple", :b => "banana"}
hash.select {|k| k == :a}  #=> {:a=>"apple"}
shweta
  • 8,019
  • 1
  • 40
  • 43
  • Works great with ruby > 1.9, but in 1.8.x it returns an array of array, which would again need to be converted to a hash. Also in 1.8.x, it won't work by just passing key as the block param, you would need to pass both k,v. so hash.select {|k, v| k == :a} – Sam Jan 11 '14 at 17:15