Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/ant/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
基于特定位置元素唯一性的数组求和合并&x2B;ruby数组_Ruby_Arrays - Fatal编程技术网

基于特定位置元素唯一性的数组求和合并&x2B;ruby数组

基于特定位置元素唯一性的数组求和合并&x2B;ruby数组,ruby,arrays,Ruby,Arrays,我有一个二维数组,如下所示 [[1, 4.0, "burger"], [1, 8.0, "tofu_log"], [2, 5.0, "burger"], [2, 6.5, "tofu_log"]] 在这里,每个元素都是餐厅id、价格和商品的集合。任务是返回唯一的餐厅id、价格总和和项目,使总和最小。我想去 [[1, 12.0, "burger, tofu_log"], [2, 11.5, "burger, tofu_log"]] 我做的如下 arr => [[1, 4.0, "bu

我有一个二维数组,如下所示

[[1, 4.0, "burger"], [1, 8.0, "tofu_log"], [2, 5.0, "burger"], [2, 6.5, "tofu_log"]]
在这里,每个元素都是餐厅id、价格和商品的集合。任务是返回唯一的餐厅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"] 

有没有不那么复杂的方法呢?

这里有一种方法

代码

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
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"]]
这是按总价排序的,从最低到最高。如果您想按从高到低的顺序进行排序,如您的示例中所示,请将排序标准
tot_price
替换为
-tot_price
,或将排序标准
.reverse
替换到最后

示例

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
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|...}
这里创建一个空哈希(“对象”)并将
arr
的每个元素传递给块。第一个元素是
[1,4.0,“burger”]
,它将以下值分配给块变量:

id    #=> 1
price #=> 4.0
item  #=> "burger"
h     #=> {}
如果在
id,price,item
Ruby周围没有括号,它会引发一个异常,因为它只需要两个参数:元素(数组)
arr
和由
each\u和\u object
创建的哈希。括号告诉Ruby,我们正在将
arr
的元素消歧为其三个组成部分

我们现在使用(aka
merge!
)将从
arr
的第一个元素形成的哈希合并到当前为空的哈希
h
。我们正在合并的哈希是

{id=>[price,[item]]} #=> {1=>[4.0,["burger"]]}
因为
h
没有键
1
,所以这个散列被合并,所以现在

h #=> {1=>[4.0,["burger"]]}
arr
的下一个元素是
[1,8.0,“豆腐日志”]
,因此块变量被赋值

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
的值,第三个值(“新值”)是我们正在合并的哈希中
1
的值

因此,键
1
的合并值变为

[12.0, ["burger, "tofu_log"]]
所以散列现在是

h => { 1=>[12.0, ["burger, "tofu_log"]] }
arr
的其余两个元素传递到块后,
每个带有\u对象的\u
返回哈希值

h => {1=>[12.0, ["burger", "tofu_log"]], 2=>[11.5, ["burger", "tofu_log"]]}
然后使用将哈希转换为所需格式的数组

对于
h
的第一个元素,块变量为

id    => 1
items => [12.0, ["burger, "tofu_log"]]
我们申请:


最后一个操作是排序,但我不确定要排序的是什么,所以我不会讨论这个问题。

这里有一种方法

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"]] 
代码

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
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"]]
这将按照从最低到最高的总价格进行排序。如果您想从最高到最低进行排序,如您的示例中所示,请将排序标准
tot_price
替换为
-tot_price
,或将
反转到最末端

示例

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
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|...}
这里创建一个空散列(“对象”),并将
arr
的每个元素传递给块。第一个是
[1,4.0,“burger”]
,它将以下值分配给块变量:

id    #=> 1
price #=> 4.0
item  #=> "burger"
h     #=> {}
如果在
id、price、item
周围没有括号,Ruby将引发一个异常,因为它只需要两个参数:
arr
的元素(数组)和
每个带有\u对象的\u创建的散列。括号告诉Ruby,我们正在将
arr
的元素消歧为它的三个组成部分

我们现在使用(aka
merge!
)将从
arr
的第一个元素形成的哈希合并到当前为空的哈希
h
。我们正在合并的哈希是

{id=>[price,[item]]} #=> {1=>[4.0,["burger"]]}
因为
h
没有键
1
,所以这个散列被合并,所以现在

h #=> {1=>[4.0,["burger"]]}
arr
的下一个元素是
[1,8.0,“豆腐日志”]
,因此块变量被赋值

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
的值,第三个值(“新值”)是我们正在合并的哈希中
1
的值

因此,键
1
的合并值变为

[12.0, ["burger, "tofu_log"]]
所以散列现在是

h => { 1=>[12.0, ["burger, "tofu_log"]] }
arr
的其余两个元素传递到块后,
每个带有\u对象的\u
返回哈希值

h => {1=>[12.0, ["burger", "tofu_log"]], 2=>[11.5, ["burger", "tofu_log"]]}
然后使用将哈希转换为所需格式的数组

对于
h
的第一个元素,块变量为

id    => 1
items => [12.0, ["burger, "tofu_log"]]
我们申请:


最后一个操作是排序,但我不确定要排序的是什么,因此我不会讨论这个问题。

您的操作是正确的。。因为我没有注意到排序的事实+1很好地使用了
group\u by
,Uri。考虑做一些消歧以便更好的可读性。例如:
arr.group_by{id,{id}
items.inject(0){tot,({,price){tot+price}
items.sort.map{124; uu,{uu,product}
。第二个建议也简化了一点
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"]]