Arrays Ruby-如何按对象数组分组?
我是ruby新手,尝试对对象数组进行分组。我有以下两个输入:Arrays Ruby-如何按对象数组分组?,arrays,ruby,group-by,Arrays,Ruby,Group By,我是ruby新手,尝试对对象数组进行分组。我有以下两个输入: Inputs: DEPT = { main_dept1: ['A', 'B', 'C'], main_dept2: ['D', 'E'] } data = [ {:id=>123, :dept=>"A", :count=>100}, {:id=>123, :dept=>"B", :count=>200}, {:id=>123,
Inputs:
DEPT = {
main_dept1: ['A', 'B', 'C'],
main_dept2: ['D', 'E']
}
data = [
{:id=>123, :dept=>"A", :count=>100},
{:id=>123, :dept=>"B", :count=>200},
{:id=>123, :dept=>"C", :count=>300},
{:id=>123, :dept=>"D", :count=>400},
{:id=>123, :dept=>"E", :count=>500},
]
我想编写一个高效的ruby代码来对数组数据进行分组,并从数组中获得下面的输出。在输出中,我想根据部门对计数进行求和
output:
{:id=>123, :main_dept1=>600, :main_dept2=>900}
请建议实现此目的的最佳方法。基于您的原始帖子,一个好方法似乎是使用的块形式将当前哈希转换为新的哈希,使用每个元素的:id值的值作为键。然后,您可以解构每个元素,并在数据数组中使用一次传递来对与部门数组匹配的:计数值求和。例如:
h = Hash.new { |hash, key| h[key] = { main_dept1: 0, main_dept2: 0 } }
data.each do |e|
id, dept, count = e[:id], e[:dept], e[:count]
h[id][:main_dept1] += e[:count] if DEPT[:main_dept1].include? dept
h[id][:main_dept2] += e[:count] if DEPT[:main_dept2].include? dept
end
h
#=> {123=>{:main_dept1=>600, :main_dept2=>900}}
h[123]
#=> {:main_dept1=>600, :main_dept2=>900}
这不会给您提供您想要的输出,但它会给您一个单独的散列,其中每个键都是一个ID。如果您想强制将其返回到一个散列数组,请继续,但是对于我来说,使用列表数据,单独的散列似乎更有用。您的里程数可能会有所不同。前言:这不是解决问题的好数据结构。您最好将这些信息存储在数据库中,而不是使用数组散列和散列数组
您也没有指定如何处理多个id
s;如果有两个或多个id
s,那么您所述的所需输出就没有意义
尽管如此,以下是我对解决方案的初步尝试:
grouped_data = data.group_by { |entry| entry[:id] }
result = grouped_data.map do |id, group|
{
id: id,
**DEPT.map do |name, depts|
{
name => group.select { |entry| depts.include?(entry[:dept]) }.map { |entry| entry[:count] }.sum
}
end.inject(&:merge)
}
end
# This gives the output of:
# result = [{:id=>123, :main_dept1=>600, :main_dept2=>900}]
我已经扩展了数组数据
,为键:id
添加了第二个值
data = [
{:id=>123, :dept=>"A", :count=>100},
{:id=>456, :dept=>"E", :count=>600},
{:id=>123, :dept=>"B", :count=>200},
{:id=>456, :dept=>"B", :count=>900},
{:id=>123, :dept=>"C", :count=>300},
{:id=>123, :dept=>"D", :count=>400},
{:id=>456, :dept=>"C", :count=>100},
{:id=>123, :dept=>"E", :count=>500},
]
我建议首先将DEPT
转换为部门到主要部门的映射:
dept_to_main_dept = DEPT.each_with_object({}) do |(main_dept,depts),h|
depts.each { |dept| h[dept] = main_dept }
end
#=> {"A"=>:main_dept1, "B"=>:main_dept1, "C"=>:main_dept1,
# "D"=>:main_dept2, "E"=>:main_dept2}
如果不这样做,您将不得不多次有效地执行以下方法,每次都需要线性搜索,这是相对低效的
def dept_to_main_dept(dept)
DEPT.find { |main_dept, arr| arr.include?(dept) }.first
end
dept_to_main_dept('D')
#=> :main_dept2
我们现在可以获得所需的哈希值,如下所示
data.group_by { |h| h[:id] }.
map do |id,arr|
arr.group_by { |g| dept_to_main_dept[g[:dept]] }.
each_with_object(id: id) do |(main_dept,e),f|
f[main_dept] = e.sum { |d| d[:count] }
end
end
#=> [{:id=>123, :main_dept1=>600, :main_dept2=>900},
# {:id=>456, :main_dept2=>600, :main_dept1=>1000}]
h = data.group_by { |h| h[:id] }
#=> {123=>[{:id=>123, :dept=>"A", :count=>100},
# {:id=>123, :dept=>"B", :count=>200},
# {:id=>123, :dept=>"C", :count=>300},
# {:id=>123, :dept=>"D", :count=>400},
# {:id=>123, :dept=>"E", :count=>500}],
# 456=>[{:id=>456, :dept=>"E", :count=>600},
# {:id=>456, :dept=>"B", :count=>900},
# {:id=>456, :dept=>"C", :count=>100}]}
g = arr.group_by { |g| dept_to_main_dept[g[:dept]] }
#=> {:main_dept1=>[{:id=>123, :dept=>"A", :count=>100},
# {:id=>123, :dept=>"B", :count=>200},
# {:id=>123, :dept=>"C", :count=>300}],
# :main_dept2=>[{:id=>123, :dept=>"D", :count=>400},
# {:id=>123, :dept=>"E", :count=>500}]}
步骤如下
data.group_by { |h| h[:id] }.
map do |id,arr|
arr.group_by { |g| dept_to_main_dept[g[:dept]] }.
each_with_object(id: id) do |(main_dept,e),f|
f[main_dept] = e.sum { |d| d[:count] }
end
end
#=> [{:id=>123, :main_dept1=>600, :main_dept2=>900},
# {:id=>456, :main_dept2=>600, :main_dept1=>1000}]
h = data.group_by { |h| h[:id] }
#=> {123=>[{:id=>123, :dept=>"A", :count=>100},
# {:id=>123, :dept=>"B", :count=>200},
# {:id=>123, :dept=>"C", :count=>300},
# {:id=>123, :dept=>"D", :count=>400},
# {:id=>123, :dept=>"E", :count=>500}],
# 456=>[{:id=>456, :dept=>"E", :count=>600},
# {:id=>456, :dept=>"B", :count=>900},
# {:id=>456, :dept=>"C", :count=>100}]}
g = arr.group_by { |g| dept_to_main_dept[g[:dept]] }
#=> {:main_dept1=>[{:id=>123, :dept=>"A", :count=>100},
# {:id=>123, :dept=>"B", :count=>200},
# {:id=>123, :dept=>"C", :count=>300}],
# :main_dept2=>[{:id=>123, :dept=>"D", :count=>400},
# {:id=>123, :dept=>"E", :count=>500}]}
h
的第一个键值对被传递到map
的块,块变量通过Ruby的应用程序赋值
我们看到id#=>123
和arr
等于散列数组
区块计算如下所示
data.group_by { |h| h[:id] }.
map do |id,arr|
arr.group_by { |g| dept_to_main_dept[g[:dept]] }.
each_with_object(id: id) do |(main_dept,e),f|
f[main_dept] = e.sum { |d| d[:count] }
end
end
#=> [{:id=>123, :main_dept1=>600, :main_dept2=>900},
# {:id=>456, :main_dept2=>600, :main_dept1=>1000}]
h = data.group_by { |h| h[:id] }
#=> {123=>[{:id=>123, :dept=>"A", :count=>100},
# {:id=>123, :dept=>"B", :count=>200},
# {:id=>123, :dept=>"C", :count=>300},
# {:id=>123, :dept=>"D", :count=>400},
# {:id=>123, :dept=>"E", :count=>500}],
# 456=>[{:id=>456, :dept=>"E", :count=>600},
# {:id=>456, :dept=>"B", :count=>900},
# {:id=>456, :dept=>"C", :count=>100}]}
g = arr.group_by { |g| dept_to_main_dept[g[:dept]] }
#=> {:main_dept1=>[{:id=>123, :dept=>"A", :count=>100},
# {:id=>123, :dept=>"B", :count=>200},
# {:id=>123, :dept=>"C", :count=>300}],
# :main_dept2=>[{:id=>123, :dept=>"D", :count=>400},
# {:id=>123, :dept=>"E", :count=>500}]}
现在,我将插入两个put
语句,以显示g
的转换是如何完成的
g.each_with_object(id: id) do |(main_dept,e),f|
puts "main_dept = #{main_dept}, e = #{e}, f = #{f}"
f[main_dept] = e.sum { |d| d[:count] }
puts " f after sum = #{f}"
end
#=> {:id=>123, :main_dept1=>600, :main_dept2=>900}
将显示以下内容(在一些手动格式化之后)
main_dept = main_dept1
e = [{:id=>123, :dept=>"A", :count=>100},
{:id=>123, :dept=>"B", :count=>200},
{:id=>123, :dept=>"C", :count=>300}]
f = {:id=>123}
f after sum = {:id=>123, :main_dept1=>600}
main_dept = main_dept2
e = [{:id=>123, :dept=>"D", :count=>400},
{:id=>123, :dept=>"E", :count=>500}]
f = {:id=>123, :main_dept1=>600}
f after sum = {:id=>123, :main_dept1=>600, :main_dept2=>900}
然后对每个值的:id
重复此操作。您尝试过什么吗?
data = [
{:id=>123, :dept=>"A", :count=>100},
{:id=>456, :dept=>"E", :count=>600},
{:id=>123, :dept=>"B", :count=>200},
{:id=>456, :dept=>"B", :count=>900},
{:id=>123, :dept=>"C", :count=>300},
{:id=>123, :dept=>"D", :count=>400},
{:id=>456, :dept=>"C", :count=>100},
{:id=>123, :dept=>"E", :count=>500},
]