Reputation: 1975
I have an array of Hashes:
[{"folder"=>"j"}, {"path"=>"p"}, {"folder"=>"b"}]
I merge them via:
flat_map(&:entries)
.group_by(&:first)
.map{|k,v| Hash[k, v.map(&:last)]}
Then I get:
[{"folder"=>["j", "b"]}, {"path"=>["p"]}]
as expected.
My question is, :folder
and :path
(I will also have more keys) can be randomly ordered. Instead of looping and checking for key names, Is it possible to get each hash separately? For example;
# After merging...
folders = elem[:folder] # => ["j", "b"]
paths = elem[:path].. # => ["p"]
Basically I would like to get :folder
and :path
without looping all the time.
Upvotes: 0
Views: 234
Reputation: 80105
ar =[{"folder"=>"j"}, {"path"=>"p"}, {"folder"=>"b"}]
elem = Hash.new{[]}
ar.each{|hash| hash.each{|k,v| elem[k] <<= v }}
folders, paths = elem.values_at("folder", "path")
Upvotes: 2
Reputation: 44601
You could use a different approach in the first place:
collection = [{"folder"=>"j"}, {"path"=>"p"}, {"folder"=>"b"}]
Using each_with_object
(or a similar approach with reduce
):
collection.each_with_object({}) do |values, s|
values.each do |key, value|
(s[key.to_sym] ||= []) << value
end
end
or group_by
and transform_values
:
collection.
group_by { |item| item.first.first.to_sym }.
transform_values { |values| values.flat_map(&:values) }
Upvotes: 2
Reputation: 592
You can solve your problem by this:
elem = [{"folder"=>["j", "b"]}, {"path"=>["p"]}]
merged = elem.reduce({}, :merge)
# => {"folder" => ["j", "b"], "path" => ["p"]}
merged["folder"]
# => ["j", "b"]
merged["path"]
# => ["p"]
Upvotes: 2