Velocity Reviews > Ruby > Why can a floating point number be used as an array index?

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

Jeff Dik
Guest
Posts: n/a

 03-29-2011
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

Sniper Abandon
Guest
Posts: n/a

 03-29-2011
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/.

Sam Duncan
Guest
Posts: n/a

 03-29-2011
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
>
>

Michael Edgar
Guest
Posts: n/a

 03-29-2011
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://www.velocityreviews.com/forums/(E-Mail Removed)
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

me@kmwhite.net
Guest
Posts: n/a

 03-29-2011
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 <(E-Mail Removed)> 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.

Xavier Noria
Guest
Posts: n/a

 03-29-2011
On Tue, Mar 29, 2011 at 10:38 PM, <(E-Mail Removed)> 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.

Josh Cheek
Guest
Posts: n/a

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

On Tue, Mar 29, 2011 at 3:59 PM, Xavier Noria <(E-Mail Removed)> wrote:

> On Tue, Mar 29, 2011 at 10:38 PM, <(E-Mail Removed)> 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

Robert Klemme
Guest
Posts: n/a

 03-30-2011
On Tue, Mar 29, 2011 at 10:02 PM, Sniper Abandon
<(E-Mail Removed)> 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
Guest
Posts: n/a

 03-30-2011
On Tue, Mar 29, 2011 at 10:38 PM, <(E-Mail Removed)> 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/