我有一个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"]
有没有那么复杂的方式?
答案 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"]]}
已经拥有密钥h
,1
的阻止
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"]]
最后的操作是排序,但我不确定要排序的内容,所以我不会讨论它。