# Why can a floating point number be used as an array index?

Discussion in 'Ruby' started by Jeff Dik, Mar 29, 2011.

1. ### Jeff DikGuest

Why can a floating point number be used as an array index? Anybody
know of a good use case for this?

irb(main):020:0> [1, 2, 3][0.3]
1
irb(main):021:0> [1, 2, 3][0.9]
1

Just curious,
Jeff

Jeff Dik, Mar 29, 2011

2. ### Sniper AbandonGuest

Jeff Dik wrote in post #989828:
> Why can a floating point number be used as an array index? Anybody
> know of a good use case for this?
>
> irb(main):020:0> [1, 2, 3][0.3]
> 1
> irb(main):021:0> [1, 2, 3][0.9]
> 1
>
> Just curious,
> Jeff

arr = [1,2,3,4....]
arr[(anyhting).to_i]

--
Posted via http://www.ruby-forum.com/.

Sniper Abandon, Mar 29, 2011

3. ### Sam DuncanGuest

How about statistical bucketing. Imagine your indexes 1, 2, and 3 are Gb

> irb

ruby-1.9.2-p0 > rss = [0.123, 1.223, 5.33, 2.294, 7.66, 5.6, 3.222,
3.88, 3.44, 1.78] # incoming rss values
=> [0.123, 1.223, 5.33, 2.294, 7.66, 5.6, 3.222, 3.88, 3.44, 1.78]

ruby-1.9.2-p0 > buckets = (0..rss.max).collect {|i| i} # bucket indexes
=> [0, 1, 2, 3, 4, 5, 6, 7]

ruby-1.9.2-p0 > rss.reduce(Hash.new(0)) {|h, v| h.tap{|h|
h[buckets[v]]+=1}} # statistics!
=> {0=>1, 1=>2, 5=>2, 2=>1, 7=>1, 3=>3}

I'm sure there are lots of (probably simpler) ways to do the same thing,
but it was a fun exercise nonetheless =]

Sam

On 30/03/11 07:35, Jeff Dik wrote:
> Why can a floating point number be used as an array index? Anybody
> know of a good use case for this?
>
> irb(main):020:0> [1, 2, 3][0.3]
> 1
> irb(main):021:0> [1, 2, 3][0.9]
> 1
>
> Just curious,
> Jeff
>
>

Sam Duncan, Mar 29, 2011
4. ### Michael EdgarGuest

Keep in mind that arrays use the implicit integer conversion protocol, =
#to_int, to make this conversion. You
can't use any old object with #to_i:

>> [1, 2, 3]["1"]

TypeError: can't convert String into Integer

Very few classes implement this protocol:

>> ObjectSpace.each_object { |a| p(a) if Module =3D=3D=3D a && =

a.instance_methods(false).include?to_int) }
Float
Integer
Numeric

I suspect the primary reason for allowing Arrays to convert floats to =
appropriate indices is to simplify calculated array
indices in *any* case. Sam gives a good example, but there are even more =
common, simple cases where
one might calculate array indices and not want to have to call #to_i =
every time. Here's one for determining
what item in a list was clicked:

chosen_item =3D items[ pixel_clicked.y / item_size ]

Michael Edgar

http://carboni.ca/

On Mar 29, 2011, at 4:17 PM, Sam Duncan wrote:

> How about statistical bucketing. Imagine your indexes 1, 2, and 3 are =

>=20
> > irb

> ruby-1.9.2-p0 > rss =3D [0.123, 1.223, 5.33, 2.294, 7.66, 5.6, 3.222, =

3.88, 3.44, 1.78] # incoming rss values
> =3D> [0.123, 1.223, 5.33, 2.294, 7.66, 5.6, 3.222, 3.88, 3.44, 1.78]
>=20
> ruby-1.9.2-p0 > buckets =3D (0..rss.max).collect {|i| i} # bucket =

indexes
> =3D> [0, 1, 2, 3, 4, 5, 6, 7]
>=20
> ruby-1.9.2-p0 > rss.reduce(Hash.new(0)) {|h, v| h.tap{|h| =

h[buckets[v]]+=3D1}} # statistics!
> =3D> {0=3D>1, 1=3D>2, 5=3D>2, 2=3D>1, 7=3D>1, 3=3D>3}
>=20
> I'm sure there are lots of (probably simpler) ways to do the same =

thing, but it was a fun exercise nonetheless =3D]
>=20
> Sam
>=20
>=20
> On 30/03/11 07:35, Jeff Dik wrote:
>> Why can a floating point number be used as an array index? Anybody
>> know of a good use case for this?
>>=20
>> irb(main):020:0> [1, 2, 3][0.3]
>> 1
>> irb(main):021:0> [1, 2, 3][0.9]
>> 1
>>=20
>> Just curious,
>> Jeff
>>=20
>> =20

>=20

Michael Edgar, Mar 29, 2011
5. ### Guest

It may do integer truncation, but we need to think of what an Array
actually is as far as the structure goes. What would one expect to get out
of [0,1,2][0.3] ? Should it be 30% of the first element? That doesn't seem
right. With arrays, you are either in one element or not. Integers make
more sense because they represent the location you're in. Either the 0
spot, 1 spot, or 2 spot. Think of a row of lockers at school. You can't be
partially between each locker. It makes more sense to only use one locker
or the next.

On Wed, 30 Mar 2011 05:08:36 +0900, Chad Perrin <> wrote:
> On Wed, Mar 30, 2011 at 03:35:21AM +0900, Jeff Dik wrote:
>> Why can a floating point number be used as an array index? Anybody
>> know of a good use case for this?
>>
>> irb(main):020:0> [1, 2, 3][0.3]
>> 1
>> irb(main):021:0> [1, 2, 3][0.9]
>> 1

>
> I don't know about why, exactly, or about use cases (though I suppose it
> might just make things easier sometimes, without errors cropping up all
> over the place if you're working with floating point numbers a lot and
> are too lazy to do integer conversions yourself). How seems, from a
> little experimenting, to be self-evident to me:
>
> \$ irb
> irb(main):001:0> [1,2,3][0.7]
> => 1
> irb(main):002:0> [1,2,3][1.7]
> => 2
> irb(main):003:0> [1,2,3][1.1]
> => 2
> irb(main):004:0> [1,2,3][-0.1]
> => 1
> irb(main):005:0> [1,2,3][-1.1]
> => 3
>
> It looks like it just does integer truncation.

, Mar 29, 2011
6. ### Xavier NoriaGuest

On Tue, Mar 29, 2011 at 10:38 PM, <> wrote:

> It may do integer truncation, but we need to think of what an Array
> actually is as far as the structure goes. What would one expect to get out
> of [0,1,2][0.3] ? Should it be 30% of the first element? That doesn't seem
> right.

Well, alternatively you could get an error.

Xavier Noria, Mar 29, 2011
7. ### Josh CheekGuest

[Note: parts of this message were removed to make it a legal post.]

On Tue, Mar 29, 2011 at 3:59 PM, Xavier Noria <> wrote:

> On Tue, Mar 29, 2011 at 10:38 PM, <> wrote:
>
> > It may do integer truncation, but we need to think of what an Array
> > actually is as far as the structure goes. What would one expect to get

> out
> > of [0,1,2][0.3] ? Should it be 30% of the first element? That doesn't

> seem
> > right.

>
> Well, alternatively you could get an error.
>
>

Seems a lot more reasonable, using floats could introduce errors:

# almost one
123.6 - 123 + 0.4 # => 0.9999999999999943

# but truncates to zero
(123.6 - 123 + 0.4).truncate # => 0

# do the same math with integers
(1236 - 1230 + 4) / 10 # => 1

Josh Cheek, Mar 29, 2011
8. ### Robert KlemmeGuest

On Tue, Mar 29, 2011 at 10:02 PM, Sniper Abandon
<> wrote:
> Jeff Dik wrote in post #989828:
>> Why can a floating point number be used as an array index? =A0Anybody
>> know of a good use case for this?
>>
>> irb(main):020:0> [1, 2, 3][0.3]
>> 1
>> irb(main):021:0> [1, 2, 3][0.9]
>> 1

> arr =3D [1,2,3,4....]
> arr[(anyhting).to_i]

No, it's using #to_int

irb(main):001:0> idx =3D Object.new
=3D> #<Object:0x1091fd74>
irb(main):002:0> %w{foo bar}[idx]
TypeError: can't convert Object into Integer
from (irb):2:in `[]'
from (irb):2
from /opt/bin/irb19:12:in `<main>'
irb(main):003:0> class <<idx
irb(main):004:1> def to_i;p "to_i";1;end
irb(main):005:1> end
=3D> nil
irb(main):006:0> %w{foo bar}[idx]
TypeError: can't convert Object into Integer
from (irb):6:in `[]'
from (irb):6
from /opt/bin/irb19:12:in `<main>'
irb(main):007:0> class <<idx
irb(main):008:1> def to_int;p "to_int";1;end
irb(main):009:1> end
=3D> nil
irb(main):010:0> %w{foo bar}[idx]
"to_int"
=3D> "bar"

#to_i is just a convenience conversion (e.g. String#to_i) while
#to_int is only used for things which *are* actually an integer. You
can see all implementators with "ri '#to_int'".

Kind regards

robert

--=20
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

Robert Klemme, Mar 30, 2011
9. ### Robert KlemmeGuest

On Tue, Mar 29, 2011 at 10:38 PM, <> wrote:
> It may do integer truncation, but we need to think of what an Array
> actually is as far as the structure goes. What would one expect to get out
> of [0,1,2][0.3] ? Should it be 30% of the first element? That doesn't seem
> right. With arrays, you are either in one element or not. Integers make
> more sense because they represent the location you're in. Either the 0
> spot, 1 spot, or 2 spot. Think of a row of lockers at school. You can't be
> partially between each locker. It makes more sense to only use one locker
> or the next.

Yes, of course. That's why Array#[] uses #to_int to determine whether
the index is integerish. The question to ask would be whether Float
should be "integerish" - Matz decided "yes" a long time ago and from
what I can recall there were not much complaints over time. From a
formal (or mathematical) point of view it's rather the other way
round: an integer /is a/ float but a float /is not an/ integer. But
Ruby is a pragmatic language and so I believe they figured that it
would be more convenient to have Float#to_int than not. YMMV though
and you can easily overwrite Float#to_int to throw.

Kind regards

robert

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

Robert Klemme, Mar 30, 2011