Rails组和对象的总和数组

生产has_many:production_lines, production_line所属项:项目, has_one项:配方, 配方has_many:recipe_lines, recipe_line归属于:item,

production_line and recipe line have attribute quantity. I need to group recipe_lines for a production by item, with quantity that equals to production_line.quantity * recipe_line.quantity

  def item_quantities
        array = production_lines.map do |p|
          p.item.recipe.recipe_lines.map do |r|
            {
              item_id: r.item_id,
              item_name: r.item.name,
              quantity: r.quantity * p.quantity
            }
          end
        end
        array.flatten(1).group_by { |p| p[:item_id] }
             .transform_values { |vals| vals.sum { |val| val[:quantity] } }
          end

返回:

item_quantities = {
1: 10,
2: 5
}

其中key是item_id,value是数量。值是正确的。

但是我想返回:

item_quantities = [
{
id: 1,
name: "Tomato",
quantity: 10,
},
{
id: 2, 
name: "Carrot",
quantity: 5
}
]

我应该如何更改解决方案以实现该目标?

评论
  • taut
    taut 回复

    First of all, your nested map followed by flatten(1) can be simplified by making the first map into flat_map. If you do this you could remove the flatten(1).

    从这一点开始,您的代码已遍历整个过程,但是您可以进行以下更改以获得所需的输出:

    1. you can group by multiple attributes, name and id. In another language you might use a tuple for this. Ruby doesn't have tuples, so we can just use a len-2 array:

      .group_by { |r| [r.item.item_id, r.item.name] }
      .transform_values { |vals| vals.sum { |val| val[:quantity] } }
      
    2. At this point you have a hash mapping [id,name] tuple to quantity:

      { [1,"foo"] => 123, [2, "bar"] => 456 }
      

      and you can coerce this to the desired data type using reduce (or each_with_object, if you prefer):

      .reduce([]) do |memo, ((id, name), quantity)|
        memo << {
          id: id,
          name: name,
          quantity: quantity
        }
      end
      

    The wierd looking ((id, name), quantity) is a kind of destructuring. See https://jsarbada.wordpress.com/2019/02/05/destructuring-with-ruby/ specifically the sections on "Destructuring Block Arguments" and "Destructuring Hashes".