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 :)
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"}
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
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"}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With