LaunchKit
All quizzes
Ruby 0 views

Indexing an Array with a Float

Question

What's the return value of the following Ruby code?

a = [21, 42, 84]

a[1.2] # => ???

The correct answer is

Explanation

TL;DR

Array#[] does not require an Integer. A Float index is converted to an integer by truncating the fractional part, so a[1.2] reads index 1 and returns 42. No rounding takes place and no error is raised.

Step by step

a = [21, 42, 84]

a[1.2] # => 42
a[1.9] # => 42

1.9 also reads index 1: the conversion truncates, it never rounds. For negative floats the truncation goes toward zero, which matters because it differs from floor:

a = [21, 42, 84]

a[-1.5]      # => 84
-1.5.to_int  # => -1
-1.5.floor   # => -2

-1.5 becomes index -1, the last element, not -2.

Under the hood

Array indexing converts its argument to a C integer. For a Float that is a direct truncation; for any other object, Ruby calls its to_int method (implicit integer conversion). Any object implementing to_int works as an index:

class MyIndex
  def to_int = 2
end

a = [21, 42, 84]

a[MyIndex.new] # => 84

An object without to_int fails. Strings deliberately do not implement it, so there is no accidental "1" indexing:

a = [21, 42, 84]

begin
  a["1"]
rescue TypeError => e
  e.message # => "no implicit conversion of String into Integer"
end

The same conversion applies to fetch, dig, at, and Array#[]=:

a = [21, 42, 84]

a.fetch(1.2) # => 42
a.dig(1.2)   # => 42

Edge cases

The float must fit in the integer range after truncation, and it must be a real number. Otherwise the conversion raises RangeError:

a = [21, 42, 84]

begin
  a[1.2e100]
rescue RangeError => e
  e.message # => "float 1.2e+100 out of range of integer"
end

begin
  a[Float::NAN]
rescue RangeError => e
  e.message # => "float NaN out of range of integer"
end

Truncating float indices is convenient in quick scripts, but an index that arrives as 1.2 usually signals a bug upstream. Convert explicitly (idx.to_i, or Integer(idx) to reject non-integral input) when the intent matters.

Share this quiz

Comments

No comments yet. Be the first.

Only used to confirm and publish your comment. Never shown publicly, never shared.

Markdown: **bold**, `code`, ```fenced blocks```, > quotes, [links](url). HTML and images are not rendered.