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

回眸只為那壹抹淺笑 提交于 2019-12-23 10:53:37

问题


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


回答1:


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"} 



回答2:


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



回答3:


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"}



回答4:


Ruby makes it possible to add that feature without much pain:

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

I hope this helps. I know it's not a built-in feature.




回答5:


{ height: '178cm', weight: '181lbs', salary: '$2/hour' }.select { |k,v| [:height, :weight].include?(k)  }


来源:https://stackoverflow.com/questions/9206881/why-cant-i-make-a-new-hash-from-selected-keys-in-ruby

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!