я был бы склонен выполнять вычисления в другом порядке:
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 #=> {}
Обратите внимание, как я разложен или «снято неоднозначность» массив, который передается в блок так, что я делаю не нужно разбирать его в блоке.
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]]
В последней матрице показано, вы имеете в виду, чтобы написать '[«U26»,«ул ", 26]' в последнем массиве. –
@Menelk, я уверен, что вы правы: неполное вырезание-вставка-редактирование. –