3

Possible Duplicate:
Array slicing in Ruby: looking for explanation for illogical behaviour (taken from Rubykoans.com)

In one of the Ruby koans, there's the following problem:

def test_slicing_arrays
  array = [:peanut, :butter, :and, :jelly]

  assert_equal _, array[0,1]
  assert_equal _, array[0,2]
  assert_equal _, array[2,2]
  assert_equal _, array[2,20]
  assert_equal _, array[4,0]
  assert_equal _, array[4,100]
  assert_equal _, array[5,0]
end

You must fill in the _ with the correct statement. The first four asserts work how I'd expect them to, but I'm confused about the last three.

array[4,0] gives back [], as does array[4,100]. At this point I figured that ranges outside of the array (greater than 3 in this case) simply return an empty array.

But array[5,0] returns nil which has now confused me completely.

Can anyone explain this behaviour?

Community
  • 1
  • 1
Martin
  • 2,865
  • 4
  • 24
  • 22
  • 1
    See http://stackoverflow.com/questions/3568222/array-slicing-in-ruby-looking-for-explanation-for-illogical-behaviour-taken-fr – nimrodm Jan 07 '12 at 19:43
  • Wish I had found that question when searching – thanks. – Martin Jan 07 '12 at 19:48
  • It was the second on the list of related questions that stackoverflow provided when you entered the question (see the right sidebar of the page). Anyway, glad I could help :) – nimrodm Jan 07 '12 at 21:10

1 Answers1

2

Ruby is not a static language, forcing you to pre-declare the size of the array. It expands arrays as you assign to a particular element.

Normally we'd append to the end of the array:

array = []       # => []
array << 1       # => [1]
array += [2]     # => [1, 2]
array.push(3)    # => [1, 2, 3]

Or push onto the front of it:

array.unshift(0) # => [0, 1, 2, 3]

to add elements, which keeps the array accumulating the values without gaps.

We can do it randomly too, which can be useful:

array[10] = 10 # => 10
array          # => [0, 1, 2, 3, nil, nil, nil, nil, nil, nil, 10]

And that's what you've encountered.


You can predefine the array to a size, but it remains dynamic:

ary = Array.new(10, nil) # => [nil, nil, nil, nil, nil, nil, nil, nil, nil, nil]
ary[0] = 0               # => 0
ary[10] = 10             # => 10
ary                      # => [0, nil, nil, nil, nil, nil, nil, nil, nil, nil, 10]
ary[12]=12               # => 12
ary                      # => [0, nil, nil, nil, nil, nil, nil, nil, nil, nil, 10, nil, 12]
the Tin Man
  • 158,662
  • 42
  • 215
  • 303
  • In addition to this: when stricter behaviour is desired, use [fetch](http://ruby-doc.org/core-1.9.3/Array.html#method-i-fetch).It can return an error (or a default value, or the result of a block) if the index lies outside the array. – steenslag Jan 07 '12 at 21:24
  • 1
    With all due respect, this doesn't answer the question with the clarity a ruby beginner needs. The [top answer](http://stackoverflow.com/a/3568281/26737) to the duplicate question is much clearer. – Manur Mar 11 '14 at 14:34
  • It appears to answer the question to the satisfaction of the person ASKING the question. That is the unit of measure here. – the Tin Man Mar 11 '14 at 16:15