Rails mapping array of hashes onto single hash
You could compose Enumerable#reduce
and Hash#merge
to accomplish what you want.
input = [{"testPARAM1"=>"testVAL1"}, {"testPARAM2"=>"testVAL2"}]
input.reduce({}, :merge)
is {"testPARAM2"=>"testVAL2", "testPARAM1"=>"testVAL1"}
Reducing an array sort of like sticking a method call between each element of it.
For example [1, 2, 3].reduce(0, :+)
is like saying 0 + 1 + 2 + 3
and gives 6
.
In our case we do something similar, but with the merge function, which merges two hashes.
[{:a => 1}, {:b => 2}, {:c => 3}].reduce({}, :merge)
is {}.merge({:a => 1}.merge({:b => 2}.merge({:c => 3})))
is {:a => 1, :b => 2, :c => 3}
Convert array of hashes to single hash with values as keys
This should do what you want
countries.each_with_object({}) { |country, h| h[country[:country].to_sym] = country[:cost] }
=> {:england=>12.34, :scotland=>56.78}
How can I convert a ruby array of hashes into a single hash?
arr = [{"name"=>"apple", "value"=>"red"},
{"name"=>"banana", "value"=>"yellow"},
{"name"=>"grape", "value"=>"purple"}]
Hash[arr.map { |h| [h["name"].to_sym , h["value"]] }]
#=> {:apple=>"red", :banana=>"yellow", :grape=>"purple"}
With Ruby 2.1+
arr.map { |h| [h["name"].to_sym , h["value"]] }.to_h
#=> {:apple=>"red", :banana=>"yellow", :grape=>"purple"}
How to convert array of hashes into a single hash and count repeated items?
You can merge to v
(within the map
call) the value of count (v.merge(:count => v.length)
), so this will add the count key to the v
hash, you'll get something like:
[
{"AVOCADO"=>{:price=>3.0, :clearance=>true, :count=>2},
{"KALE"=>{:price=>3.0, :clearance=>false, :count=>2}
]
But anyways the values for :count
are going to be wrong.
In the other hand, you can get all the keys from each hash in cart_items, merge the hashes, and then merge a new key with the count of that key in the stored keys array:
def consolidate_cart(items)
items_keys = items.flat_map(&:keys)
items.inject(:merge).map do |key, value|
{ key => value.merge(count: items_keys.count(key)) }
end
end
p consolidate_cart(cart_items)
# [{"AVOCADO"=>{:price=>3.0, :clearance=>true, :count=>2}}, {"KALE"=>{:price=>3.0, :clearance=>false, :count=>1}}]
A part by part view of the method functioning:
You map the keys of each hash item (items.flat_map(&:keys)
):
["AVOCADO", "AVOCADO", "KALE"]
You merge the hash within items
(items.inject(:merge)
):
{"AVOCADO"=>{:price=>3.0, :clearance=>true}, "KALE"=>{:price=>3.0, :clearance=>false}}
When you iterate over the previous generated hash, you merge to each hash value the count key ({ key => value.merge(count: items_keys.count(key)) }
):
# {:price=>3.0, :clearance=>true}
# {:count=>2}
# => {:price=>3.0, :clearance=>true, :count => 2}
I've already seen my answer doesn't correspond with the expected output. This does:
def consolidate_cart(items)
items.inject(:merge).each_with_object(items: items.flat_map(&:keys)) do |(k, v), hash|
hash[k] = v.merge(count: hash[:items].count(k))
end.reject { |k, _| k == :items }
end
How to create an array of hashes by mapping 2 hashes in ruby on rails
You can use a regular Array#map
for this:
first_array_of_hash = [{:name => "John", :age => 34, :nullable => 'yes'},{:name => "Rose", :age => 30, :nullable => 'no'}]
second_hash = {:field_name => "", :field_age => nil, :field_nullable => false, :field_default => ""}
def transform(object)
{
field_name: object[:name],
field_age: object[:age],
field_nullable: object[:mode] == 'nullable'
}
end
result = first_array_of_hash.map do |object|
second_hash.merge(transform(object))
end
puts result
How to separate an array of hashes into different arrays if a key is equal?
Given:
tst=[
{"user_id"=>2, "user_name"=>"Pepo", "beneficiary_document"=>"43991028", "calification_by_qualifier"=>5.0},
{"user_id"=>2, "user_name"=>"Pepo", "beneficiary_document"=>"71730550", "calification_by_qualifier"=>3.84},
{"user_id"=>3, "user_name"=>"Carlos", "beneficiary_document"=>"43991028", "calification_by_qualifier"=>0.0},
{"user_id"=>3, "user_name"=>"Carlos", "beneficiary_document"=>"71730550", "calification_by_qualifier"=>3.4}
]
You can use .group_by to get a hash of elements by key. In this case, use the key ["beneficiary_document"]
passed to the block and you will get a hash of arrays by that key -- two in this case.
You can do:
tst.group_by { |h| h["beneficiary_document"] }
# {"43991028"=>[{"user_id"=>2, "user_name"=>"Pepo", "beneficiary_document"=>"43991028", "calification_by_qualifier"=>5.0}, {"user_id"=>3, "user_name"=>"Carlos", "beneficiary_document"=>"43991028", "calification_by_qualifier"=>0.0}], "71730550"=>[{"user_id"=>2, "user_name"=>"Pepo", "beneficiary_document"=>"71730550", "calification_by_qualifier"=>3.84}, {"user_id"=>3, "user_name"=>"Carlos", "beneficiary_document"=>"71730550", "calification_by_qualifier"=>3.4}]}
To see it pretty printed:
require "pp"
PP.pp(tst.group_by {|h| h["beneficiary_document"] },$>,120)
{"43991028"=>
[{"user_id"=>2, "user_name"=>"Pepo", "beneficiary_document"=>"43991028", "calification_by_qualifier"=>5.0},
{"user_id"=>3, "user_name"=>"Carlos", "beneficiary_document"=>"43991028", "calification_by_qualifier"=>0.0}],
"71730550"=>
[{"user_id"=>2, "user_name"=>"Pepo", "beneficiary_document"=>"71730550", "calification_by_qualifier"=>3.84},
{"user_id"=>3, "user_name"=>"Carlos", "beneficiary_document"=>"71730550", "calification_by_qualifier"=>3.4}]}
You can also achieve the same result with a hash that returns an array as a default procedure, then call .map
over tst
and push the hash into the array by that key:
h=Hash.new { |h,k| h[k]=[] }
tst.map { |eh| h[eh["beneficiary_document"]].push(eh) }
Or, combine that into a single statement:
tst.each_with_object(Hash.new { |h,k| h[k]=[] }) { |g,h|
h[g["beneficiary_document"]].push(g)}
All three methods create identical hashes. The first, .group_by
, is the easiest.
Converting an array of hashes to ONE hash in Ruby
I think the key to the solution is Hash[]
, which will create a Hash based on an array of key/values, i.e.
Hash[[["key1", "value1"], ["key2", "value2"]]]
#=> {"key1" => "value1", "key2" => "value2"}
Just add a set of map
, and you have a solution!
result = [
{"id_t"=>["1"], "transcript_t"=>["I am a transcript ONE"]},
{"id_t"=>["2"], "transcript_t"=>["I am a transcript TWO"]},
{"id_t"=>["3"], "transcript_t"=>["I am a transcript THREE"]}
]
Hash[result.map(&:values).map(&:flatten)]
Reducing an array of hashes into new hash
This will work:
arr.each_with_object({}) do |obj, hash|
%i[all_sales direct_sales referred_sales].each do |sym|
hash[sym] = hash[sym].to_i + obj[sym]
end
end
It's one iteration, you can write the nested loop as 3 different lines, but it's a bit cleaner this way in my opinion.
Note: calling to_i
while getting previous value of hash[sym]
as initially it is nil
and nil.to_i == 0
. Alternatively, you can initialize all unknown counts with 0, like this:
arr.each_with_object(Hash.new(0)) do |obj, hash|
%i[all_sales direct_sales referred_sales].each do |sym|
hash[sym] += obj[sym]
end
end
Related Topics
How to Reference Global Variables and Class Variables
Undefined Method 'Devise' for User
How to List All Files in an S3 Folder Using Aws-Sdk Gem in Ruby on Rails
Passing Parameters to Erb View
How to Initialize an Array Inside a Hash in Ruby
How to Save Unescaped & in Nokogiri Xml
Instance_Eval Block Not Supplied
Get SASS from Database (Compile Passed Data Instead of Reading from File)
Is Every Relavant Calculation Performed Every Time the Page Is Loaded
How to Fix a Deadlock Caused by Open
Ruby: How to Define a Class Method in a Module
Rails: How to Make Date Strftime Aware of the Default Locale
Why Is It Best to Store a Telephone Number as a String VS. Integer
Is There a Way in Ruby/Rails to Execute Code That Is in a String
How to Find the Source File for a Rake Task
How to Convert Array of Activerecord Models to CSV