简体   繁体   中英

How do I define and reference multi-dimensional arrays in Ruby?

I have a global definition in my controller for a multi-dimensional array as follows:

def ch
  @ch = Array.new(1){[]}
  @ch[0][0] = "Option 1"
  @ch[0][1] = "Option 2"
end

(I'm not sure if this is the best to do the array but I found an example online to do it this way)

in my controller action called "test", I am not able to print the values of the array appropriately.

def test
  logger.debug ch
  logger.debug ch[0]
  logger.debug ch[1]
  logger.debug ch[0][0]
  logger.debug ch[0][1]
end

stdout shows the following for the 5 logger statements respectively

Option 2
79
112
1
1

Why do the integers show? Any idea how I get the array values Option 1 and Option 2 to show?

If I define the array in the action itself (not doing it globally outside the action), I get the expected results ie ch[0][0] shows Option 1 and ch[0][1] shows Option 2. Eventually, I want to have access to the array in my view. There may be a better way to do this.

There are a few things going on here.

  1. In Ruby, the last line of a method is that method's return value; so the return value of ch is "Option 2" . Let's verify this on IRB, the Ruby REPL:

     [BinaryMuse ~]: irb ruby-1.9.2-p136 :001 > def ch ruby-1.9.2-p136 :002?> ary = Array.new(1){[]} ruby-1.9.2-p136 :003?> ary[0][0] = "Option 1" ruby-1.9.2-p136 :004?> ary[0][1] = "Option 2" ruby-1.9.2-p136 :005?> end => nil ruby-1.9.2-p136 :006 > ch => "Option 2" 
  2. In test , you are calling the ch method rather than referencing the @ch variable. logger.debug ch is thus equivalent to logger.debug "Option 2" , and thus ch[0] is the first character of "Option 2", which is "O", which has the ASCII code 79. The same goes for ch[1] , which is "p", with the ASCII code 112. ch[0][0] returns the least significant bit of 79, which is 1, and so on.

  3. Even if you change test to use @ch instead of calling the ch method, @ch still isn't defined since you haven't yet called ch to set up the @ch variable during your request. You can do this via a before_filter in your controller:

     class WhateverController before_filter :ch def ch # your code end def test logger.deubg @ch # etc. end end 

You're confusing methods and variables. When you do

def ch
...
end

you're defining a method and that method returns the last thing that was evaluated in it. In this case, the last thing you did in the method is:

@ch[0][1] = "Option 2" 

which evaluates to "Option 2" . Therefore, when you call your method ch it will return "Option 2" . That's why

logger.debug ch

logs "Option 2" .

Now, inside your method ch you're creating an instance variable @ch . To log the values the way you wanted to, you would have to change your logging code like this:

logger.debug @ch
logger.debug @ch[0]
logger.debug @ch[1]
logger.debug @ch[0][0]
logger.debug @ch[0][1]

But, for this to work, you have to ensure that the code which creates the @ch instance variable has been executed before executing the test method. One way to do this is by having your ch method called using before_filter :

class YourControllerClassName
  before_filter :ch

Why do the integers show?

Because the ch method return a "Option 2" string and calling the [] method on a string will return the integer value (ASCII code) of the letter at the index you wanted to get (ie ch[1] returns the int value of the "p" character).

Any idea how I get the array values Option 1 and Option 2 to show?

Define the ch method as:

def ch
  ch = Array.new(1){[]}
  ch[0][0] = "Option 1"
  ch[0][1] = "Option 2"
  return ch
end

Or leave it as is and modivie the test method:

def test
  ch # initialize the @ch instance variable
  logger.debug @ch
  logger.debug @ch[0]
  logger.debug @ch[1]
  logger.debug @ch[0][0]
  logger.debug @ch[0][1]
end

I think this will be helpful. Cheers.

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