Where is the method for the array
I'm pretty much trying to mimic a class method where
, but instead on an instance, that instance is an array of hashes. For example: this exists as a class method Class.where(:name => "Joe")
, so I want to be able to do this:
@joe = {:name => "Joe", :title => "Mr.", :job => "Accountant"}
@kelly = {:name => "Kelly", :title => "Ms.", :job => "Auditor"}
@people = [@joe, @kelly]
and call this:
@people.where(:name => 'Joe')
which should return an object @joe
.
How should I write this?
As I understand it, the task you want to define Array#where
. Here you are:
▶ class Array
▷ def where hash
▷ return nil unless hash.is_a? Hash # one might throw ArgumentError here
▷ self.select do |e|
▷ e.is_a?(Hash) && hash.all? { |k, v| e.key?[k] && e[k] == v }
▷ end
▷ end
▷ end
#⇒ :where
▶ @people.where(:name => 'Joe')
#⇒ [
# [0] {
# :job => "Accountant",
# :name => "Joe",
# :title => "Mr."
# }
# ]
▶ @people.where(:name => 'Joe', :job => 'Accountant')
#⇒ [
# [0] {
# :job => "Accountant",
# :name => "Joe",
# :title => "Mr."
# }
# ]
▶ @people.where(:name => 'Joe', :job => 'NotAccountant')
#⇒ []
Hope it helps.
UPD Slightly updated function to distinguish between values nil
and missing keys. Credits to @CarySwoveland.
You can use Enumerable # find to get the first element that matches:
@people.find { |p| p[:name] == 'Joe' }
or List # find_all to retrieve all elements that match:
@people.find_all { |p| p[:name] == 'Joe' }
@people.find{|p| p[:name] =='Joe'}
or
@people.find(:name => 'Joe').first
or
@people.select{|p| p[:name ]== 'Joe'}.first
Using the method:
def find_user params
@people.find(params).first
end
find_user name:'Joe'
=> {:name=>"Joe", :title=>"Mr.", :job=>"Accountant"}
This is slightly different from Rails' where
, more like find_by
: where
returns a relation, a collection of instances. In fact, the implementations of both are about the same and use different methods Enumerable
:
@people.select { |h| h[:name] == 'Joe' } # where-like
@people.find { |h| h[:name] == 'Joe' } # find_by-like
You can generalize it at any time by fulfilling Enumerable#all?
the hash condition.
If you're talking about a real array of hashes and an inactive entry:
@some_array.select {|item| item["search_key"] = 'search val' }