Ruby 通过比较一个值进行散列合并
Ruby hash merge by comparing a value
我有以下哈希数组
[{: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}]
我需要使用 Day 键值合并那些记录,预期结果是
[{: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}]
提前致谢..
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
TLDR:
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
解释:
假设我们在 data
变量中有您的数据:
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}]
然后我们可以根据:Day
值对数组进行分组(group_by
),得到
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}]}
生成的散列的键是日期,值是数据散列数组。我们只对 values
and map
数据哈希数组与单个合并数据哈希感兴趣:
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
inject
将两个数据哈希(a
和 b
)合并为一个新的哈希。
这给了我们最终的结果:
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:如果您不熟悉这些方法,阅读有关这些方法的 ruby 文档可能会有所帮助。我为每个使用的方法添加了 link。
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
我不知道你将如何处理 Rent、Bond 和 RentInAdvance,所以我只找到最大值。
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
我有以下哈希数组
[{: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}]
我需要使用 Day 键值合并那些记录,预期结果是
[{: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}]
提前致谢..
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
TLDR:
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
解释:
假设我们在 data
变量中有您的数据:
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}]
然后我们可以根据:Day
值对数组进行分组(group_by
),得到
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}]}
生成的散列的键是日期,值是数据散列数组。我们只对 values
and map
数据哈希数组与单个合并数据哈希感兴趣:
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
inject
将两个数据哈希(a
和 b
)合并为一个新的哈希。
这给了我们最终的结果:
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:如果您不熟悉这些方法,阅读有关这些方法的 ruby 文档可能会有所帮助。我为每个使用的方法添加了 link。
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
我不知道你将如何处理 Rent、Bond 和 RentInAdvance,所以我只找到最大值。
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