Ruby,计入数组内部

时间:2015-04-14 12:41:37

标签: ruby

我有一个带有字符串和2个int的数组数组:

[["u31", 12, 23], ["u26", 12, 23], ["u26", 11, 3]]

我首先需要根据字符串和累积值arr [1]和arr [2]

合并多个这些数组的出现次数。

所以对于这个例子,我需要这个:

[["u31", 12, 23], ["u26", 23, 26]]

然后将这两个值分开:

[
  ["u31", "dl", 12],
  ["u31", "ul", 23],
  ["u26", "dl", 23],
  ["u31", "ul", 26]
]

然后按降序排序。

我该怎么做?

1 个答案:

答案 0 :(得分:4)

我倾向于以不同的顺序执行计算:

arr = [["u31", 12, 23], ["u26", 12, 23], ["u26", 11, 3]]

arr.each_with_object({}) { |(s,*v),h| ['d1','ul'].zip(v).each { |t,x|
      h.update([s,t]=>x) { |_,ox,nx| ox+nx } } }.
    map { |(s,t),x| [s,t,x] }.
    sort.
    reverse
  #=> [["u31", "ul", 23],
  #    ["u31", "d1", 12],
  #    ["u26", "ul", 26],
  #    ["u26", "d1", 23]] 

让我们看看这里发生了什么。

enum0 = arr.each_with_object({})
  #=> #<Enumerator: [["u31", 12, 23], ["u26", 12, 23],
  #                  ["u26", 11, 3]]:each_with_object({})> 

我们可以将枚举数转换为数组,以查看each将传递给块的值:

enum0.to_a
  #=> [[["u31", 12, 23], {}], [["u26", 12, 23], {}],
  #    [["u26", 11, 3], {}]] 

我们可以使用Enumerator#next获取枚举器的每个值,并手动将其分配给块变量:

(s,*v),h = enum0.next
  #=> [["u31", 12, 23], {}] 
s #=> "u31" 
v #=> [12, 23] 
h #=> {}

注意我如何分解或消除歧义&#34;传递给块的数组,以便我不必在块内分开。

a = ['d1','ul'].zip(v)
  #=> [["d1", 12], ["ul", 23]]

出现:另一位调查员:

enum1 = a.each
  #=> #<Enumerator: [["d1", 12], ["ul", 23]]:each> 
t,x = enum1.next
  #=> ["d1", 12] 
h.update([s,t]=>x)
  #=> {}.update(["u31,"d1"]=>12)
  #=> {["u31", "d1"]=>12} 

Hash#update(又名merge!)有一个块,用于确定正在构建的哈希(h)和哈希中存在的键的值被合并({["u31", "d1"]=>12})。由于h为空,因此该块不会用于第一次合并。

接下来,

t,x = enum1.next
  #=> ["ul", 23] 
h.update([s,t]=>x)
  #=> {["u31", "d1"]=>12}.update(["u31", "ul"]=>23) 
  #=> {["u31", "d1"]=>12, ["u31", "ul"]=>23} 

其中update返回h的新值。我们已完成enum1,因此each会传递enum0的下一个值并执行类似的计算:

(s,*v),h = enum0.next
  #=> [["u26", 12, 23], {["u31", "d1"]=>12, ["u31", "ul"]=>23}] 
['d1','ul'].zip(v).each { |t,x| h.update([s,t]=>x) {|_,ox,nx| ox+nx }}
  #=> [["d1", 12], ["ul", 23]]
h #=> {["u31", "d1"]=>12, ["u31", "ul"]=>23, ["u26", "d1"]=>12,
  #    ["u26", "ul"]=>23} 

我们现在将enum0的第三个和最后一个值传递给块。同样,计算是相同的,除了update步骤:

(s,*v),h = enum0.next
  #=> [["u26", 11, 3],
  #    {["u31", "d1"]=>12, ["u31", "ul"]=>23, ["u26", "d1"]=>12,
  #     ["u26", "ul"]=>23}]
a = ['d1','ul'].zip(v)
  #=> [["d1", 11], ["ul", 3]]
enum1 = a.each
  #=> #<Enumerator: [["d1", 11], ["ul", 3]]:each> 
t,x = enum1.next
  #=> ["d1", 11] 
h.update([s,t]=>x)
  #=> {["u31", "d1"]=>12, ["u31", "ul"]=>23,
  #    ["u26", "d1"]=>12, ["u26", "ul"]=>23}.update(["u26","d1"],11)
  #   h and the hash being merged both have the key ["u26", "d1"], 
  #    so the merged value is determined by update's block:
  #=> { |_,ox,nx| ox+nx } => 12+11 => 23
  #=> {["u31", "d1"]=>12, ["u31", "ul"]=>23,
  #    ["u26", "d1"]=>11, ["u26", "ul"]=>23} 
t,x = enum1.next
  #=> ["ul", 3] 
h.update([s,t]=>x)
  #=> {["u31", "d1"]=>12, ["u31", "ul"]=>23,
  #    ["u26", "d1"]=>11, ["u26", "ul"]=>26}

我们现在基本上已经完成了。我们只需将此哈希转换为所需形式的数组:

a = h.map { |(s,t),x| [s,t,x] }
  #=> [["u31", "d1", 12], ["u31", "ul", 23],
  #    ["u26", "d1", 11], ["u26", "ul", 26]]

并排序:

a.sort.reverse
  #=> [["u31", "ul", 23],
  #    ["u31", "d1", 12],
  #    ["u26", "ul", 26],
  #    ["u26", "d1", 11]]