简体   繁体   中英

Ruby 2d array of hashes with runtime-decided length

I am trying to do something like this in a ruby module:

def initialize
  super
  @@main_array = Array.new(16) { Array.new} 
end

def add_hash(hash={})
  @@main_array[get_id] << hash
end
# Where get_id returns 0-15

I expect each sub-array to have only the hashes that were added to it. Instead, all sub-arrays have all hashes added. Inspecting the array shows that the sub-arrays all share object ID's.

I'm not sure why this is the case. What am I missing here?

Edit:

Here's the exact code I'm using:

module Manager
  def initialize
    super
    @@main_array = Array.new(BaseCompany.get_number_thread(), Array.new())
  end

  def self.check_and_add_thread_activity(activity={})
    action = Hash.new
    action[:id] = @@main_array[BaseCompany.get_current_threadid].length +1 
    action[:name] = activity[:name]
    action[:added] = true
    @@main_array[BaseCompany.get_current_threadid] << action
    return action
  end

end

Check_and_add is called by other parts of the code, as the individual threads execute functionality

Okay, I've actually solved it. In the comments below someone mentioned that this:

Array.new(16,Array.new)

Would cause the sub-arrays to have the same object ID. Someone else corrected him saying it shouldn't happen, but this was the case in my code. I replaced that line with the recommended:

Array.new(16) {Array.new} 

And this worked just fine.

For reference, I'm using JRuby 1.7.3

Array.new(size, object)

main_array = Array.new(16, Array.new)

is equivalent to :

row = Array.new
main_array = Array.new(16,row)

or just

main_array = [row, row, row, row, row, row, row, row, row, row, row, row, row, row, row, row]

So you have 16 times exactly the same object (one empty Array). Modifying one element will automatically modifiy all the others :

p main_array
#=> [[], [], [], [], [], [], [], [], [], [], [], [], [], [], [], []]

row << 1

p main_array
#=> [[1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1]]

Array.new(size){ }

main_array = Array.new(16){ Array.new }

is equivalent to :

main_array = (1..16).map{ Array.new }

or :

main_array = [Array.new, Array.new, Array.new, Array.new, Array.new, Array.new, Array.new, Array.new, Array.new, Array.new, Array.new, Array.new, Array.new, Array.new, Array.new, Array.new]

Now you have 16 empty Arrays, but they are all different objects. Modifying one element won't modify any of the other arrays :

main_array = Array.new(16){ Array.new }

p main_array
#=> [[], [], [], [], [], [], [], [], [], [], [], [], [], [], [], []]

main_array[0] << 1

p main_array
#=> [[1], [], [], [], [], [], [], [], [], [], [], [], [], [], [], []]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM