基于特定位置+红宝石阵列的元素唯一性的数组求和和合并

时间:2014-05-02 17:42:17

标签: ruby arrays

我有一个2D数组,如下所示

[[1, 4.0, "burger"], [1, 8.0, "tofu_log"], [2, 5.0, "burger"], [2, 6.5, "tofu_log"]]

这里,每个元素都是restaurant_id,price和item的集合。任务是返回唯一的restaurant_id,价格总和以及总和应该最小的项目。我想得到

[[1, 12.0, "burger, tofu_log"], [2, 11.5, "burger, tofu_log"]]

我已经完成了如下

arr
  => [[1, 4.0, "burger"], [1, 8.0, "tofu_log"], [2, 5.0, "burger"], [2, 6.5, "tofu_log"]] 
ids = arr.map{|i| i[0]}.uniq
  => [1, 2] 
a = ids.map{|id| arr.map{|i| i if i[0] == id }.compact}
  => [[[1, 4.0, "burger"], [1, 8.0, "tofu_log"]], [[2, 5.0, "burger"], [2, 6.5, "tofu_log"]]] 
a.map{|x| [x[0][0], x.map{|y| y[1]}.inject(:+), x.map{|i| i[2..-1]}.join(', ')] }.sort{|x| x[1]}.first
=> [2, 11.5, "burger, tofu_log"] 

有没有那么复杂的方式?

2 个答案:

答案 0 :(得分:3)

arr.group_by { |rest_id, _| rest_id }.map do |rest_id, items| 
  [rest_id, 
   items.map { |_, price| price }.inject(:+), 
   items.sort.map { |_, _, product| product }.join(", ") ]
end
# => [[1, 12.0, "burger, tofu_log"], [2, 11.5, "burger, tofu_log"]] 

答案 1 :(得分:1)

这是一种方法。

<强>代码

def doit(arr)
  arr.each_with_object({}) { |(id,price,item),h| h.update({id=>[price,[item]]}) \
       {|_,(o_price,o_item), (n_price,n_item)|[o_price+n_price, o_item+n_item]}}
     .map { |id, (tot_price,*items)| [id, tot_price, items].flatten }
     .sort_by { |_,tot_price| tot_price }
end

对总价格进行排序,从最低到最高。如果您想要从最高到最低排序,请在示例中将排序条件tot_price替换为-tot_price,或将.reverse添加到最后。

示例

arr = [[1, 4.0, "burger"], [1, 8.0, "tofu_log"],
       [2, 5.0, "burger"], [2, 6.5, "tofu_log"]]

doit(arr)
  #=> [[2, 11.5, "burger", "tofu_log"], [1, 12.0, "burger", "tofu_log"]]

<强>解释

让我们逐行看一下,使用上面的例子,

arr.each_with_object({}) { |(id,price,item),h|...}

这里Enumerable#each_with_object创建一个空哈希(“对象”)并将arr的每个元素传递给块。第一个是[1, 4.0, "burger"],它将以下值分配给块变量:

id    #=> 1
price #=> 4.0
item  #=> "burger"
h     #=> {}

如果我们在id,price,item周围没有括号,那么Ruby会引发异常,因为它只需要两个参数:arr的元素(数组)和{{1}创建的哈希}。括号告诉Ruby我们each_with_object的元素消除歧义为其三个组成部分。

我们现在使用Hash#update(又名arr)将从merge!的第一个元素形成的哈希合并到当前为空的哈希arr中。我们合并的哈希是

h

由于{id=>[price,[item]]} #=> {1=>[4.0,["burger"]]} 没有密钥h,因此合并了此哈希,所以现在

1

h #=> {1=>[4.0,["burger"]]} 的下一个元素是arr,因此为块变量赋值

[1, 8.0, "tofu_log"]

我们现在尝试合并哈希

id    #=> 1
price #=> 8.0
item  #=> "tofu_log" (yuk!)
h     #=> {1=>[4.0,["burger"]]}

但由于哈希{id=>[price,[item]]} #=> {1=>[8.0,["tofu_log"]]} 已经拥有密钥h1的阻止

update

用于确定键{|k,(o_price,o_item), (n_price,n_item)| [o_price + n_price, o_item + n_item]} 的合并值(块的存在理由)。

此块具有以下值:

1

第一个块变量是键,它等于{|1,(4.0,["burger"]), (8.0,["tofu_log"])| [4.0 + 8.0, ["burger"]+["tofu_log"|} ,但由于我们没有使用它,我已经用下划线(占位符)替换它,以强调它没有被使用。第二个块变量(“旧值”)是合并散列中1的值,第三个值(“新值”)是我们合并的散列中1的值。 / p>

密钥1的合并值因此变为

1

所以哈希现在是

[12.0, ["burger, "tofu_log"]]

h => { 1=>[12.0, ["burger, "tofu_log"]] } 的其余两个元素传递给块后,arr返回哈希

each_with_object

然后我们使用Enumerable#map将散列转换为具有所需格式的数组。

对于h => {1=>[12.0, ["burger", "tofu_log"]], 2=>[11.5, ["burger", "tofu_log"]]} 的第一个元素,块变量是

h

我们申请Array#flatten

id    => 1
items => [12.0, ["burger, "tofu_log"]]

最后的操作是排序,但我不确定要排序的内容,所以我不会讨论它。