如何对一个值的重复次数求和并将其添加到 Ruby 中键的两个值中?

SEV*_*VEN 2 ruby ruby-on-rails ruby-hash

我试图为目录上的每种扩展类型创建一个具有一个键的哈希值。我想为每个键添加两个值:重复扩展名的次数以及具有该扩展名的所有文件的总大小。

\n

与此类似的东西:

\n

{".md" => {"ext_reps" => 6, "ext_size_sum" => 2350}, ".txt" => {"ext_reps" => 3, "ext_size_sum" => 1300}}

\n

但我\xc2\xb4m坚持这一步:

\n
hash = Hash.new{|hsh,key| hsh[key] = {}}\next_reps = 0\next_size_sum = 0\n\nDir.glob("/home/computer/Desktop/**/*.*").each do |file|\n  hash[File.extname(file)].store "ext_reps", ext_reps\n  hash[File.extname(file)].store "ext_size_sum", ext_size_sum \nend\n\np hash\n
Run Code Online (Sandbox Code Playgroud)\n

得到这个结果:

\n

{".md" => {"ext_reps" => 0, "ext_size_sum" => 0}, ".txt" => {"ext_reps" => 0, "ext_size_sum" => 0}}

\n

我找不到增加ext_reps和的方法ext_siz_sum

\n

谢谢

\n

Car*_*and 5

假设绘制的文件扩展名和文件大小如下。

files = [{ ext: 'a', size: 10 },
         { ext: 'b', size: 20 },
         { ext: 'a', size: 30 },
         { ext: 'c', size: 40 },
         { ext: 'b', size: 50 },
         { ext: 'a', size: 60 }]
Run Code Online (Sandbox Code Playgroud)

您可以使用Hash#group_by和Hash#transform_values。

files.group_by { |h| h[:ext] }.
      transform_values do |arr|
        { "ext_reps"=>arr.size, "ext_size_sum"=>arr.sum { |h| h[:size] } }
      end
        #=> {"a"=>{"ext_reps"=>3, "ext_size_sum"=>100},
        #    "b"=>{"ext_reps"=>2, "ext_size_sum"=>70},
        #    "c"=>{"ext_reps"=>1, "ext_size_sum"=>40}}
Run Code Online (Sandbox Code Playgroud)

请注意,第一个计算如下。

files.group_by { |h| h[:ext] }
  #=> {"a"=>[{:ext=>"a", :size=>10}, {:ext=>"a", :size=>30},
  #          {:ext=>"a", :size=>60}],
  #    "b"=>[{:ext=>"b", :size=>20}, {:ext=>"b", :size=>50}],
  #    "c"=>[{:ext=>"c", :size=>40}]}
Run Code Online (Sandbox Code Playgroud)

另一种方法是使用Hash#update(又名Hash#merge!)和Hash#merge的形式,它们使用块来计算正在合并的两个哈希中存在的键的值。(当带有 key 的键值对k被合并到正在构建的散列中时,Ruby 不会查阅该块(h当h没有 key时k)。)

有关返回正在合并的哈希的公共键值的块的三个参数的说明,请参阅文档。

files.each_with_object({}) do |g,h|
   h.update(g[:ext]=>{"ext_reps"=>1, "ext_size_sum"=>g[:size]}) do |_k,o,n|
     o.merge(n) { |_kk, oo, nn| oo + nn }
   end
end
  #=> {"a"=>{"ext_reps"=>3, "ext_size_sum"=>100},
  #    "b"=>{"ext_reps"=>2, "ext_size_sum"=>70},
  #    "c"=>{"ext_reps"=>1, "ext_size_sum"=>40}}
Run Code Online (Sandbox Code Playgroud)

_k我为“外部”和“内部”哈希(分别为和)的公共键选择了_kk以下划线开头的名称,以向读者表明它们未在块计算中使用。这是常见的做法。

请注意,此方法避免创建类似于创建的临时哈希group_by,因此往往比第一种方法使用更少的内存。