1

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?

2
  • Off-topic, but you should really use the #nil? predicate instead of comparing objects with nil ;) Commented Oct 18, 2011 at 15:45
  • 1
    or not even bothering with any nil comparison -- if destination.position Commented Oct 18, 2011 at 15:49

4 Answers 4

3

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.

Sign up to request clarification or add additional context in comments.

1 Comment

You really can't spend too much time learning about what Enumerable can do for you.
2
   @orderedDestinations[destination.position] is nil so: 

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

   -> nil[destination.id]

3 Comments

True, but this is really more of a comment than an answer.
Not really, that is the answer. He asked what is he doing wrong and I told him. Is concise and to the point..no need to stretch things out. Downvote is really unnecesary.
Generally when someone asks what they're doing wrong, it is appropriate to tell them how to do it right. I agree the downvote is unnecessary, but it wasn't me. :)
1

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.

Comments

0

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.

3 Comments

Then you're creating a hash. Arrays and hashes are not the same.
I think this is a reasonable thing to do considering that an arbitrary id value is being used as the key here.
@tadman I was pointing out that he's creating a hash and not an array because it isn't clear that he knows there is a difference.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.