我有一个带有字符串和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]
]
然后按降序排序。
我该怎么做?
答案 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]]