Sebastien
Sebastien

Reputation: 6660

Mutidimensional array with ruby on rails

I have to reorder my hash of Destinations, so i want to make an array in an array like this :

@orderedDestinations = Array.new 
@destinations.each do |destination|
  if (destination.position != nil)
    @orderedDestinations[destination.position][destination.id] = destination
  end
end

I got this error :

You have a nil object when you didn't expect it!
You might have expected an instance of Array.
The error occurred while evaluating nil.[]=

What i am doing wrong?

Upvotes: 1

Views: 110

Answers (4)

coreyward
coreyward

Reputation: 80128

If you want to sort @destinations by Destination#position you should just do this:

@orderedDestinations = @destinations.sort_by(&:position)

http://ruby-doc.org/core-1.9.2/Enumerable.html#method-i-sort_by

Done deal.

Upvotes: 3

tadman
tadman

Reputation: 211740

In Ruby, most things are nil unless explicitly initialized as something. All elements of a new array, for instance, are this by default if they don't exist or haven't been assigned to previously. Like this:

test = [ 1, 2 ]
# => [1,2]
test[1]
# => 2
test[2]
# => nil

What you probably want to do is initialize the second level of the array as required. You can employ a pattern like this:

@orderedDestinations = [ ] # Empty array
@destinations.each do |destination|
  if (destination.position)
    # If this element of the array has not been initialized,
    # populate it with a new empty array.
    destination_set = @orderedDestinations[destination.position] ||= [ ]

    # Put something in this second-level array spot
    destination_set[destination.id] = destination
  end
end

The choice of Array [ ] or Hash { } for your second level entry depends on the kind of data you're storing in it. Hash tables handle arbitrary identifiers easily, where an Array works best with sequential numbers typically starting at or near zero. If you initialize element X of an array, that array becomes size X+1 automatically.

Upvotes: 1

Sebastien
Sebastien

Reputation: 6660

Yes, Thank you. The solution is to add this line :

@orderedDestinations[destination.position] ||= {}

So the complete code is :

@orderedDestinations = Array.new
@destinations.each do |destination|
  if (destination.position != nil)
    @orderedDestinations[destination.position] ||= {}
    @orderedDestinations[destination.position][destination.id] = destination
  end
end

Thank you.

Upvotes: 0

daniel
daniel

Reputation: 9845

   @orderedDestinations[destination.position] is nil so: 

   @orderedDestinations[destination.position][destination.id] really is:

   -> nil[destination.id]

Upvotes: 2

Related Questions