Reputation: 3878
i have the following array of Hashes
[{:Day=>"May 2015", :Rent=>0, :Bond=>0, :RentInAdvance=>0},
{:Day=>"May 2015", :Rent=>0, :Bond=>0, :RentInAdvance=>450},
{:Day=>"May 2015", :Rent=>0, :Bond=>750, :RentInAdvance=>0},
{:Day=>"Jun 2015", :Rent=>600, :Bond=>0, :RentInAdvance=>0},
{:Day=>"Jul 2015", :Rent=>600, :Bond=>0, :RentInAdvance=>0},
{:Day=>"Dec 2015", :Rent=>600, :Bond=>0, :RentInAdvance=>0}]
I need to merge those record using the Day key value, expected result is
[{:Day=>"May 2015", :Rent=>0, :Bond=>750, :RentInAdvance=>450},
{:Day=>"Jun 2015", :Rent=>600, :Bond=>0, :RentInAdvance=>0},
{:Day=>"Jul 2015", :Rent=>600, :Bond=>0, :RentInAdvance=>0},
{:Day=>"Dec 2015", :Rent=>600, :Bond=>0, :RentInAdvance=>0}]
Thanks in advance..
Upvotes: 2
Views: 126
Reputation: 96
i = 0
while i < arr.length-1
j = i+1
while j < arr.length-1
#Compare dates of hash with another_hash
if arr[i][:Day] == arr[j][:Day]
#If matches, add another_hash values(numerical) to corresponding keys of hash
arr[i].merge!(arr[j]) {|key, vi, vj| vi.is_a?(Fixnum) ? (vi + vj) : vi }
#Delete another_hash after its values has been added to hash
arr.delete_at(j)
#Next, compare at same index since it now points to next hash after its previous value(another_hash) has been deleted
j -= 1
end
j += 1
end
i += 1
end
arr
Upvotes: 0
Reputation: 449
origin = [{:Day=>"May 2015", :Rent=>0, :Bond=>0, :RentInAdvance=>0},
{:Day=>"May 2015", :Rent=>0, :Bond=>0, :RentInAdvance=>450},
{:Day=>"May 2015", :Rent=>0, :Bond=>750, :RentInAdvance=>0},
{:Day=>"Jun 2015", :Rent=>600, :Bond=>0, :RentInAdvance=>0},
{:Day=>"Jul 2015", :Rent=>600, :Bond=>0, :RentInAdvance=>0},
{:Day=>"Dec 2015", :Rent=>600, :Bond=>0, :RentInAdvance=>0}]
result = origin.reduce({}) do |memo, obj|
day = obj[:Day]
memo[day] ||= Hash.new(0)
memo[day][:Rent] = [memo[day][:Rent], obj[:Rent]].max
memo[day][:Bond] = [memo[day][:Bond], obj[:Bond]].max
memo[day][:RentInAdvance] = [memo[day][:RentInAdvance], obj[:RentInAdvance]].max
memo
end.reduce([]) do |memo, obj|
memo << {:Day => obj[0]}.merge(obj[1])
end
p result
I don't know how you will do with Rent, Bond and RentInAdvance, so I just find the maximum.
Upvotes: 0
Reputation: 45943
data = [{:Day=>"May 2015", :Rent=>0, :Bond=>0, :RentInAdvance=>0},
{:Day=>"May 2015", :Rent=>0, :Bond=>0, :RentInAdvance=>450},
{:Day=>"May 2015", :Rent=>0, :Bond=>750, :RentInAdvance=>0},
{:Day=>"Jun 2015", :Rent=>600, :Bond=>0, :RentInAdvance=>0},
{:Day=>"Jul 2015", :Rent=>600, :Bond=>0, :RentInAdvance=>0},
{:Day=>"Dec 2015", :Rent=>600, :Bond=>0, :RentInAdvance=>0}]
days = data.map{|d| d[ :Day ]}.uniq
def sum_by_day_for data, key
data.map{| d| d[ key ]}.inject( :+ )
end
sum = days.map do |day|
same_days = data.select{|d| d[ :Day ] == day}
{ Day:day,
Rent:sum_by_day_for( same_days, :Rent ),
Bond:sum_by_day_for( same_days, :Bond ),
RentInAdvance:sum_by_day_for( same_days, :RentInAdvance )}
end
puts sum
Upvotes: 0
Reputation: 13574
data.group_by do |d|
d[:Day]
end.values.map do |days|
days.inject do |a,b|
{
Day: a[:Day],
Rent: a[:Rent] + b[:Rent],
Bond: a[:Bond] + b[:Bond],
RentInAdvance: a[:RentInAdvance] + b[:RentInAdvance]
}
end
end
Let's say we have your data in the data
variable:
data = [{:Day=>"May 2015", :Rent=>0, :Bond=>0, :RentInAdvance=>0},
{:Day=>"May 2015", :Rent=>0, :Bond=>0, :RentInAdvance=>450},
{:Day=>"May 2015", :Rent=>0, :Bond=>750, :RentInAdvance=>0},
{:Day=>"Jun 2015", :Rent=>600, :Bond=>0, :RentInAdvance=>0},
{:Day=>"Jul 2015", :Rent=>600, :Bond=>0, :RentInAdvance=>0},
{:Day=>"Dec 2015", :Rent=>600, :Bond=>0, :RentInAdvance=>0}]
Then we can group (group_by
) the array by the :Day
value, to get
grouped_data = data.group_by do |d|
d[:Day]
end
# {"May 2015"=>
# [{:Day=>"May 2015", :Rent=>0, :Bond=>0, :RentInAdvance=>0},
# {:Day=>"May 2015", :Rent=>0, :Bond=>0, :RentInAdvance=>450},
# {:Day=>"May 2015", :Rent=>0, :Bond=>750, :RentInAdvance=>0}],
# "Jun 2015"=>[{:Day=>"Jun 2015", :Rent=>600, :Bond=>0, :RentInAdvance=>0}],
# "Jul 2015"=>[{:Day=>"Jul 2015", :Rent=>600, :Bond=>0, :RentInAdvance=>0}],
# "Dec 2015"=>[{:Day=>"Dec 2015", :Rent=>600, :Bond=>0, :RentInAdvance=>0}]}
The key of the resulting hash is the date, and the value is an array of data-hashes. We are only interested in the values
and map
the array of data-hashes to a single merged data-hash with:
merged_data = grouped_data.values.map do |days|
days.inject do |a,b|
{
Day: a[:Day],
Rent: a[:Rent] + b[:Rent],
Bond: a[:Bond] + b[:Bond],
RentInAdvance: a[:RentInAdvance] + b[:RentInAdvance]
}
end
end
The inject
merges two data-hashes (a
and b
) into a new hash.
Which gives us the final result:
puts merged_data
# {:Day=>"May 2015", :Rent=>0, :Bond=>750, :RentInAdvance=>450}
# {:Day=>"Jun 2015", :Rent=>600, :Bond=>0, :RentInAdvance=>0}
# {:Day=>"Jul 2015", :Rent=>600, :Bond=>0, :RentInAdvance=>0}
# {:Day=>"Dec 2015", :Rent=>600, :Bond=>0, :RentInAdvance=>0}
PS: It might help to read the ruby documentation on the methods, if you're not familiar with them. I've added a link to each method used.
Upvotes: 1