Reputation: 3307
Perhaps I'm missing something obvious. It seems tricky to filter a hash by another hash or multiple key/value pairs.
fruit = [
{ name: "apple", color: "red", pieable: true },
{ name: "orange", color: "orange", pieable: false },
{ name: "grape", color: "purple", pieable: false },
{ name: "cherry", color: "red", pieable: true },
{ name: "banana", color: "yellow", pieable: true },
{ name: "tomato", color: "red", pieable: false }
]
filter = { color: "red", pieable: true }
# some awesome one-liner? would return
[
{ name: "apple", color: "red", pieable: true },
{ name: "cherry", color: "red", pieable: true }
]
The array of hashes I don't think is the problem. I don't even know how to test a hash by another arbitrary hash. I'm using Rails so anything out of active_support etc is fine.
Upvotes: 3
Views: 1077
Reputation: 1424
Try this
fruit.select{ |hash| (filter.to_a & hash.to_a) == filter.to_a }
=> [{:name=>"apple", :color=>"red", :pieable=>true},
{:name=>"cherry", :color=>"red", :pieable=>true}]
Upvotes: 0
Reputation: 3307
Tony Arcieri (@bascule) gave this really nice solution on twitter.
require 'active_support/core_ext' # unneeded if you are in a rails app
fruit.select { |hash| hash.slice(*filter.keys) == filter }
And it works.
# [{:name=>"apple", :color=>"red", :pieable=>true},
# {:name=>"cherry", :color=>"red", :pieable=>true}]
Upvotes: 1
Reputation: 110675
I'd be inclined to use Enumerable#group_by for this:
fruit.group_by { |g| { color: g[:color], pieable: g[:pieable] } }[filter]
#=> [{:name=>"apple", :color=>"red", :pieable=>true},
# {:name=>"cherry", :color=>"red", :pieable=>true}]
Upvotes: 1
Reputation: 7744
COULD be made into a one liner. But multi-line is cleaner.
fruit.select do |hash| # or use select!
filter.all? do |key, value|
value == hash[key]
end
end
Upvotes: 2
Reputation: 62648
Not the most efficient (you could just use an array form of filter
to avoid repeated conversions), but:
fruit.select {|f| (filter.to_a - f.to_a).empty? }
Upvotes: 1
Reputation: 34308
If you allow two lines it could also be made into an efficient "one-liner" like so:
keys, values = filter.to_a.transpose
fruit.select { |f| f.values_at(*keys) == values }
Upvotes: 1