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

This has been undermining me for a while. Itโ€™s not difficult, but I donโ€™t know why there is no easy way to do it already, and Iโ€™m sure there are, and I donโ€™t see it.

I just want to take a hash, for example:

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 great:

 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 obviously are two million easy ways to do this, but I wonder if there is something that I missed, or a good non-obvious reason, is this not a standard and normal thing? Without this, I end up using something like:

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

which is not the end of the world, but he is not very beautiful. It seems like this should be part of a regular dictionary. What am I missing here?

(related questions include the following: Ruby Hash whitelist filter ) (this blog post has exactly the same result as me, but again, why is this not built-in? http://matthewbass.com/2008/06/ 26 / picking-values-from-ruby-hashes / )

update:

I am using Rails, which has ActiveSupport :: CoreExtensions :: Hash :: Slice, which works exactly the way I want, so the problem is solved, but still ... maybe someone will find their answer here :)

+4
source share
4 answers

I always thought it was a strange omission, but there really is no simple standard method for this.

Your example above may be unnecessarily slow because it iterates over all the hash records, whether we need them or not, and then iterates over the array of key parameters. This code should be a little faster (assuming it matters - and I did not try to compare it).

 class Hash def pick(*keys) values = values_at(*keys) Hash[keys.zip(values)] end end 
+4
source

Ruby allows you to add this function without any problems:

 class Hash alias old_accessor :[] def [](*key) key.is_a?(Array) ? self.dup.delete_if{|k, v| !key.include? k} : old_accessor(key) end end 

Hope this helps. I know this is not a built-in function.

+1
source

select deserves at least mention:

 cars = {:bob => 'Pontiac', :fred => 'Chrysler', :lisa => 'Cadillac', :mary => 'Jaguar'} people = [:bob, :lisa] p cars.select{|k, _| people.include?(k)} #=> {:bob=>"Pontiac", :lisa=>"Cadillac"} 
+1
source
 { height: '178cm', weight: '181lbs', salary: '$2/hour' }.select { |k,v| [:height, :weight].include?(k) } 
0
source

Source: https://habr.com/ru/post/1395553/


All Articles