Bula
Bula

Reputation: 2792

Populating a ruby array reading from a file

I'm trying to populate a multi-dimensional array in ruby by reading from a file. Here is the code:

class Maze
    attr_accessor :array



    def initialize(filename) 
        handler = File.open(filename,"r")
        @array = Array.new(10,Array.new(10))
        n = 0;
        i = 0;
         while(line = handler.gets) do
            i = 0

            line.chomp.each_char do |char|
                p char
                @array[n][i] = char
                i += 1
            end #iterator over character in every line
            n += 1
         end #iterator over file lines
        handler.close
    end #constructor
end #class
a = Maze.new("maze.txt")
p a.array

Here is the content of the file:

##########
#        #
# ####   #
# #  #   #
@ #  #   ?
# #  #   #
# #      #
# ####   #
#        #
##########

However this line of code (the last line of code)

p a.array

Will print an array 10 by 10 but full of "#" symbols. No spaces nor "?". Something important to note is that

p char

In the block where I assign the array with values prints the right characters. It prints spaces at the right time and question marks etc... I know it's something very simple but it's bugging me and I think I need a fresh pair of eyes to look over it

Why is it that the array has only "#" symbols. Why aren't all the other characters such as " ", "@", "?" in my array? Is the assigning in my code wrongly coded

Upvotes: 0

Views: 379

Answers (2)

the Tin Man
the Tin Man

Reputation: 160551

I'd write the code differently. It's not quite clear what you're trying to do, so here's two different things I'd do:

class Maze
  attr_accessor :array

  def initialize(filename) 
    @array = []
    File.foreach(filename) do |line|
      @array << line.chomp
    end 
  end 

end 

a = Maze.new("maze.txt")
p a.array
puts a.array

Which outputs:

["##########", "#        #", "# ####   #", "# #  #   #", "@ #  #   ?", "# #  #   #", "# #      #", "# ####   #", "#        #", "##########"]
##########
#        #
# ####   #
# #  #   #
@ #  #   ?
# #  #   #
# #      #
# ####   #
#        #
##########

Or:

class Maze
  attr_accessor :array

  def initialize(filename) 
    @array = []
    File.foreach(filename) do |line|
      @array << line.chomp.split('')
    end 
  end 

end 

a = Maze.new("maze.txt")
p a.array
puts a.array.map(&:join)

which outputs:

[["#", "#", "#", "#", "#", "#", "#", "#", "#", "#"], ["#", " ", " ", " ", " ", " ", " ", " ", " ", "#"], ["#", " ", "#", "#", "#", "#", " ", " ", " ", "#"], ["#", " ", "#", " ", " ", "#", " ", " ", " ", "#"], ["@", " ", "#", " ", " ", "#", " ", " ", " ", "?"], ["#", " ", "#", " ", " ", "#", " ", " ", " ", "#"], ["#", " ", "#", " ", " ", " ", " ", " ", " ", "#"], ["#", " ", "#", "#", "#", "#", " ", " ", " ", "#"], ["#", " ", " ", " ", " ", " ", " ", " ", " ", "#"], ["#", "#", "#", "#", "#", "#", "#", "#", "#", "#"]]
##########
#        #
# ####   #
# #  #   #
@ #  #   ?
# #  #   #
# #      #
# ####   #
#        #
##########

The primary problem in your code is you're using array references when you assign to the sub-arrays, which results in them all pointing to the same memory. I think you did that because you're used to another language where you have to predefine your array size. Ruby is more friendly than that, allowing us to append to an array easily. I used to << operator, but other methods exist to do the same thing; << is easier to see and understand.

Instead of opening the file, then using a while loop to iterate over it, it's more idiomatic to use foreach, which accomplishes the same thing and automatically closes the file when the block exits.

Also, instead of iterating over each line's characters, simply split the line using split('') which will return an array of characters. Append that to @array and move on.

Upvotes: 1

Hector Correa
Hector Correa

Reputation: 26690

The culprit is the way you are initializing the array in this line:

@array = Array.new(10,Array.new(10))

this is creating an array of 10 elements and it is initializing all of them with a pointer to another array of 10 elements. All the 10 elements will be sharing the same array. You can see a simplified example in here:

b = Array.new(3,Array.new(3))
b[0][0] = '00'
puts b   # you'll see '00' printed 3 times!

One way to fix your program will be to create the array of rows first, then then initialize each row to a different array:

@array = Array.new(10)
for i in 0..9
    # initialize each row to a unique array
    @array[i] = Array.new(10)
end
# the rest of your code

Upvotes: 0

Related Questions