Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't I make a new hash from selected keys in ruby?

Tags:

ruby

hash

This has been bugging me for a while. It's not a difficult thing, but I don't know why there's no easy way to do it already, and I bet there is and I don't see it.

I just want to take a hash, like this:

cars = {:bob => 'Pontiac', :fred => 'Chrysler', 
        :lisa => 'Cadillac', :mary => 'Jaguar'}

and do something like

cars[:bob, :lisa]

and get

{:bob => 'Pontiac', :lisa => 'Cadillac'}

I did this, which works fine:

class Hash
  def pick(*keys)
    Hash[select { |k, v| keys.include?(k) }]
  end
end

ruby-1.8.7-p249 :008 > cars.pick(:bob, :lisa)
=> {:bob=>"Pontiac", :lisa=>"Cadillac"} 

There's obviously a zillion easy ways to do this, but I'm wondering if there's something built in I've missed, or a good an un-obvious reason it's not a standard and normal thing? Without it, I wind up using something like:

chosen_cars = {:bob => cars[:bob], :lisa => cars[:lisa]}

which isn't the end of the world, but it's not very pretty. It seems like this should be part of the regular vocabulary. What am I missing here?

(related questions, include this: Ruby Hash Whitelist Filter) (this blog post has precisely the same result as me, but again, why isn't this built in? http://matthewbass.com/2008/06/26/picking-values-from-ruby-hashes/ )

update:

I'm using Rails, which has ActiveSupport::CoreExtensions::Hash::Slice, which works exactly as I want it to, so problem solved, but still... maybe someone else will find their answer here :)

like image 627
stephan.com Avatar asked Feb 09 '12 07:02

stephan.com


3 Answers

Just to help others, some years after the fact:

Slice works nicely to do what I wanted.

> cars.slice(:bob, :lisa)
=> {:bob=>"Pontiac", :lisa=>"Cadillac"} 
like image 87
stephan.com Avatar answered Nov 10 '22 07:11

stephan.com


I've always thought that was a weird omission as well, but there really is no simple, standard method for that.

Your example above might be unnecessarily slow because it iterates over all the hash entries whether we need them or not, and then repeatedly searches through the keys parameter array. This code should be a bit faster (assuming that would ever matter -- and I haven't tried to benchmark it).

class Hash
  def pick(*keys)
    values = values_at(*keys)
    Hash[keys.zip(values)]
  end
end
like image 43
Steve Jorgensen Avatar answered Nov 10 '22 07:11

Steve Jorgensen


select deserves at least to be mentioned:

cars = {:bob => 'Pontiac', :fred => 'Chrysler', 
        :lisa => 'Cadillac', :mary => 'Jaguar'}
people = [:bob, :lisa]

p cars.select{|k, _| people.include?(k)}
#=> {:bob=>"Pontiac", :lisa=>"Cadillac"}
like image 25
steenslag Avatar answered Nov 10 '22 09:11

steenslag