Ruby按字段

时间:2018-02-23 02:57:12

标签: arrays ruby

我有一个对象数组,我想按字段1分组,按字段2分组。一个示例是具有product字段和title字段的类price。 在一系列产品中,我有多个价格不同的手套,以及不同价格的多个帽子。我希望有一个具有不同标题的数组,汇总同一标题下的所有价格。

有一个明显的解决方案,迭代数组并使用哈希,但我想知道是否有一个" ruby​​方式"做这样的事情?我已经看过很多例子,其中Ruby有一些独特的功能,可以很好地应用于某些场景,并且是一个Ruby新手,我很好奇。

由于

2 个答案:

答案 0 :(得分:2)

有一种方法transform_values added in ruby 2.4或者如果你require 'active_support/all',你可以这样做:

products = [
  {type: "hat", price: 1, name: "fedora"},
  {type: "hat", price: 2, name: "sombrero"},
  {type: "glove", price: 3, name: "mitten"},
  {type: "glove", price: 4, name: "wool"}
]

result = products
  .group_by { |product| product[:type] }
  .transform_values { |vals| vals.sum { |val| val[:price] } }
# => {"hat"=>3, "glove"=>7}

答案 1 :(得分:1)

根据询问您的数据是什么,我对这个问题有点不清楚,所以我最终得到了这个:

Product = Struct.new(:title, :price)

products = [
  Product.new("big hat", 1),
  Product.new("big hat", 2),
  Product.new("small hat", 3),
  Product.new("small hat", 4),
  Product.new("mens glove", 8),
  Product.new("mens glove", 9),
  Product.new("kids glove", 1),
  Product.new("kids glove", 2)
]

鉴于这些数据,我就是如何建立一个包含给定标题所有价格总和的数据结构:

sum_by_title = products.inject({}) do |sums, product|
  if sums[product.title]
    sums[product.title] += product.price
  else
    sums[product.title] = product.price
  end
  sums
end

这会产生:

{"big hat"=>3, "small hat"=>7, "mens glove"=>17, "kids glove"=>3}

解释:

Ruby inject获取初始值并将其作为“备忘录”传递给迭代块。这里,{}是初始值。块的返回值作为备忘录传递到下一次迭代。

product.title用作散列键,运行总和存储在散列值中。 if语句是必要的,因为第一次遇到产品标题时,该标题的存储值为nil且不能递增。

由于hash default value构造函数的隐藏魔法,我可能不会发送此代码,但是可以在没有if语句的情况下编写相同的代码:

sum_by_title = products.inject(Hash.new { 0 }) do |sums, product|
  sums[product.title] += product.price
  sums
end

希望你像我一样享受Ruby!