1

I have some array deep_array that's deep in a hash and takes time to access, I also have a variable (my_local_variable) pointing to deep_array and some other local array new_array. I need to set deep_array to new_array through my_local_variable.

Something equivalent to one of these:

my_local_variable.map!.with_index {|_, i| new_array[i]}

my_local_variable.each_with_index {|_, i| b[i] = new_array[i]}

but much faster

Edit: speed

This is a rough idea of the situation I'm dealing with:

(in reality it's deeper but i'm doing fewer writes)

require 'benchmark'
H = {[1,2,3]=>[2,3,4],[3,4,5]=>[4,5,6],[5,6,7]=>[6,7,8]}
h = H[[1,2,3]]

Benchmark.bmbm(15) do |i|
  i.report('local reference') {1_000_000.times {|i| h[0] = i}}
  i.report('          index') {1_000_000.times {H[[1,2,3]][0] = i}}
end

Gives:

Rehearsal ---------------------------------------------------
local reference   0.230000   0.010000   0.240000 (  0.234168)
          index   5.780000   0.040000   5.820000 (  5.851909)
------------------------------------------ total: 6.060000sec

                      user     system      total        real
local reference   0.220000   0.000000   0.220000 (  0.226742)
          index   5.770000   0.030000   5.800000 (  5.830011)
Asone Tuhid
  • 539
  • 4
  • 13
  • Does `deep_array` need to be set to `new_array` (i.e. `deep_array.object_id == new_array.object_id` when you're done) or do you just need them to have the same contents? – mu is too short Jun 20 '17 at 21:42
  • In the hash where ever deep_array is being referenced, you can switch that with new_array reference right, so you don't have to copy. {key => deep_array} you can change it to { key => new_array }, not sure if this is what you are looking for. – ugandharc18 Jun 20 '17 at 21:43
  • @muistooshort no, `new array` is a cached value in this case so it should stay as it is – Asone Tuhid Jun 20 '17 at 22:38
  • @Ucpuzz yes but the position of `deep_array` is more like `hash[a][b][c][d]` and `a, b, c and d` are arrays themselves and have to be hashed, it's too slow to access `deep_array`, that's why I have a local reference – Asone Tuhid Jun 20 '17 at 22:41
  • If you had a reference one level above what you have then maybe `whatever[:your_array] = new_array.dup` would work, I don't know if that would be significantly faster than manually copying element by element though. If you have such complicated and deeply nested data then maybe you should rethink how you're managing your data. – mu is too short Jun 20 '17 at 23:48
  • @muistooshort it's not storage, they're values used in calculation, I've found that `[[array, array], ...]` works better than `{array => array, ...}` so I have a few levels nesting. That's better but still not quite the same, I'm doing a lot of lookups and replacements and the array containing `deep_array` is quite big so (at least in benchmarks) modifying the reference is still faster than modifying `container[deep_array]` – Asone Tuhid Jun 21 '17 at 00:13

1 Answers1

0

Tell me if I'm wrong but Array#replace seems faster than any of the current answers as it doesn't require the new array to be .duplicated and doesn't need another reference to be created:

new_arrays = 1000000.times.map {4.times.map {rand 10}}

require 'benchmark'

Benchmark.bmbm(18) do |i|
  i.report('     find, replace') do
    hash = {0=>{1=>{2=>{3=>[]}}}}
    1000000.times do |j|
      hash[0][1][2][3].replace new_arrays[j]
    end
  end

  i.report('         find, dup') do
    hash = {0=>{1=>{2=>{3=>[]}}}}
    1000000.times do |j|
      hash[0][1][2][3] = new_arrays[j].dup
    end
  end

  i.report('reference, replace') do
    hash = {0=>{1=>{2=>{3=>[]}}}}
    reference = hash[0][1][2][3]
    1000000.times do |j|
      reference.replace new_arrays[j]
    end
  end

  i.report('    above ref, dup') do
    hash = {0=>{1=>{2=>{3=>[]}}}}
    above = hash[0][1][2]
    1000000.times do |j|
      above[3] = new_arrays[j].dup
    end
  end
end

Gives:

Rehearsal ------------------------------------------------------
     find, replace   1.670000   0.090000   1.760000 (  1.791100)
         find, dup   2.010000   0.110000   2.120000 (  2.193884)
reference, replace   0.460000   0.000000   0.460000 (  0.470288)
    above ref, dup   1.390000   0.020000   1.410000 (  1.421624)
--------------------------------------------- total: 5.750000sec

                         user     system      total        real
     find, replace   0.960000   0.020000   0.980000 (  1.039140)
         find, dup   1.720000   0.010000   1.730000 (  1.753176)
reference, replace   0.470000   0.000000   0.470000 (  0.472988)
    above ref, dup   1.360000   0.020000   1.380000 (  1.384833)

And the differences would be even more drastic if I were indexing with arrays

Asone Tuhid
  • 539
  • 4
  • 13