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

J

Jeff Dik

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
 
S

Sniper Abandon

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]
 
S

Sam Duncan

How about statistical bucketing. Imagine your indexes 1, 2, and 3 are Gb
of RSS or something.
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


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
 
M

Michael Edgar

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:
TypeError: can't convert String into Integer

Very few classes implement this protocol:
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
(e-mail address removed)
http://carboni.ca/

How about statistical bucketing. Imagine your indexes 1, 2, and 3 are = Gb of RSS or something.
=20
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
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
 
M

me

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.

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.
 
X

Xavier Noria

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.
 
J

Josh Cheek

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

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
 
R

Robert Klemme

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/
 
R

Robert Klemme

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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,734
Messages
2,569,441
Members
44,832
Latest member
GlennSmall

Latest Threads

Top