Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/22.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
Ruby 分组/总结两个哈希的最有效方法?_Ruby - Fatal编程技术网

Ruby 分组/总结两个哈希的最有效方法?

Ruby 分组/总结两个哈希的最有效方法?,ruby,Ruby,我有两个散列,其中包含一些需要聚合的数据。第一个是哪些id(id_1、id_2、id_3、id_4)属于哪个类别(a、b、c)的映射: 第二个哈希值保存给定日期(日期1、日期2、日期3)每个id发生的事件数: 我想要的是得到每个类别(a、b、c)的总事件数。对于上面的示例,结果如下所示: hash_3 = {'a' => (5+6+8+0+6), 'b' => (0+0+1), 'c' => (10+1)} 我的问题是,大约有5000个类别,每个类别通常指向1到3个ID,每个

我有两个散列,其中包含一些需要聚合的数据。第一个是哪些id(id_1、id_2、id_3、id_4)属于哪个类别(a、b、c)的映射:

第二个哈希值保存给定日期(日期1、日期2、日期3)每个id发生的事件数:

我想要的是得到每个类别(a、b、c)的总事件数。对于上面的示例,结果如下所示:

hash_3 = {'a' => (5+6+8+0+6), 'b' => (0+0+1), 'c' => (10+1)}
我的问题是,大约有5000个类别,每个类别通常指向1到3个ID,每个ID具有30个或更多日期的事件计数。所以这需要相当多的计算。在Ruby中进行分组最有效的方法是什么

更新 这就是我到目前为止所尝试的(花了6-8秒,速度非常慢):

另外,我正在使用Ruby 2.3。

理论
5000*3*30
不是很多。Ruby可能最多需要一秒钟来完成这种工作

默认情况下,哈希查找是快速的,您将无法进行太多优化

您可以预先计算
hash\u 2\u sum
,不过:

hash_2_sum = {
  'id_1' => 5+6+8, 
  'id_2' => 0+6, 
  'id_3' => 0+0+1, 
  'id_4' => 10+1
}
使用
hash\u 2\u sum
lookup在
hash1
上循环一次,就完成了

代码 您的示例已更新为一些
nil
值。您需要使用删除它们,并确保在未找到具有以下内容的元素时,总和为
0

注 不是很容易读懂

您可以将
每个_与_对象一起使用
数组#to _h

result = [1, 2, 3].each_with_object({}) do |i, hash|
  hash[i] = i * i
end
#=> {1=>1, 2=>4, 3=>9}

result = [1, 2, 3].map { |i| [i, i * i] }.to_h
#=> {1=>1, 2=>4, 3=>9}

首先,创建一个中间散列,其中包含
散列2
的总和:

hash_4 = hash_2.map{|k, v| [k, v.values.inject(:+)]}.to_h
# => {"id_1"=>19, "id_2"=>6, "id_3"=>1, "id_4"=>11}
然后做最后的总结:

hash_3 = hash_1.map{|k, v| [k, v.map{|k| hash_4[k]}.inject(:+)]}.to_h
# => {"a"=>25, "b"=>1, "c"=>11}

我在手机上写这封信,所以我现在无法测试,但看起来没问题

g = hash_2.each_with_object({}) { |(k,v),g| g[k] = v.values.compact.sum }
hash_3 = hash_1.each_with_object({}) { |(k,v),h| h[k] = g.values_at(*v).sum }

不要害怕尝试一些东西,因为有450000个计数;事实上这并不多。您可能会惊讶于解决方案的运行速度。(如果没有,我们将在这里帮助优化它!)请参阅更新A在实际应用程序中您是否知道数组的大致大小
hash_1.values.uniq
?对于大多数类别,大约5000-10000个,只有一个ID对应。对于一些类别2-3 ID相对应。对于这些数字,我看不到比答案中包含的更有效的方法。Ruby 2.4可以,OP在2.4之前的Ruby版本中使用Ruby 2.3(除非也使用Rails,它已经有一段时间了
sum
),将
sum
替换为
reduce(:+)
。请注意,OP还更新了他的输入数据。现在值可以是
nil
。@Eric,谢谢。我刚才注意到了。当我看到另一条评论时,我知道它是关于什么的,它来自谁。:-)不仅仅是
注入(:+)
?@CarySwoveland:
[]注入(:+)#=>nil
[]注入(0,:+)#=>0
 {}.tap do |res|
    hash_1.each do |cat, ids|
      res[cat] = total_event_per_ids(ids)
    end
  end
result = [1, 2, 3].each_with_object({}) do |i, hash|
  hash[i] = i * i
end
#=> {1=>1, 2=>4, 3=>9}

result = [1, 2, 3].map { |i| [i, i * i] }.to_h
#=> {1=>1, 2=>4, 3=>9}
hash_4 = hash_2.map{|k, v| [k, v.values.inject(:+)]}.to_h
# => {"id_1"=>19, "id_2"=>6, "id_3"=>1, "id_4"=>11}
hash_3 = hash_1.map{|k, v| [k, v.map{|k| hash_4[k]}.inject(:+)]}.to_h
# => {"a"=>25, "b"=>1, "c"=>11}
g = hash_2.each_with_object({}) { |(k,v),g| g[k] = v.values.compact.sum }
hash_3 = hash_1.each_with_object({}) { |(k,v),h| h[k] = g.values_at(*v).sum }