我有一个对象数组,我想按字段1分组,按字段2分组。一个示例是具有product
字段和title
字段的类price
。
在一系列产品中,我有多个价格不同的手套,以及不同价格的多个帽子。我希望有一个具有不同标题的数组,汇总同一标题下的所有价格。
有一个明显的解决方案,迭代数组并使用哈希,但我想知道是否有一个" ruby方式"做这样的事情?我已经看过很多例子,其中Ruby有一些独特的功能,可以很好地应用于某些场景,并且是一个Ruby新手,我很好奇。
由于
答案 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!