Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Arrays Ruby-如何按对象数组分组?_Arrays_Ruby_Group By - Fatal编程技术网

Arrays 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,

我是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, :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},
]