Robert Klemme
10/12/2007 2:42:00 PM
2007/10/12, Yossef Mendelssohn <ymendel@pobox.com>:
> On Oct 11, 9:55 pm, Brian Adkins <lojicdot...@gmail.com> wrote:
> > On Oct 11, 9:30 pm, Marek Kasperkiewicz <m.kasperkiew...@gmail.com>
> > wrote:
> >
> > > If i try this
> > > puts (1..10).max
> > > it runs fine.
> > > If i try this
> > > puts (1..100000000).max
> > > It is extremely slow. Instead of using straight math max= 100000000-1
> > > it uses some king of interator to find out the value of max.
> > > What is the catch here?
> >
> > Well, one advantage of (1..N).max compared to your 'straight math'
> > method is the former provides the correct answer and the latter does
> > not. :)
> >
> > However, for efficiency, if for some reason you don't want to simply
> > use max = N, you'll find max = (1..N).end is much faster than max =
> > (1..N).max since it doesn't look at each element in the range.
> >
> > The Enumerable#max method is generalized to also work for cases such
> > as max = [1,10,100,10,1].max
>
> I was thinking Range#last, but that has the same problem as Range#end
> (probably one is an alias for the other).
>
> (1..10).last (or end) => 10
> (1..10).max => 10
>
> (1...10).last (or end) => 10
> (1...10).max => 9
>
> What you want is something like
>
> class Range
> def quick_max
> last - (exclude_end? ? 1 : 0)
> end
> end
>
> Of course, if you're not using Fixnums, this is wrong. Maybe if
> classes defined prec (instead of only succ), this could be easy.
I believe not. #max *has* to use <=> for a proper result. Although it
might be common that <=> and #succ represent the same ordering this is
not required. Actually there is a pretty straightforward example:
irb(main):001:0> ("a".."aa").last
=> "aa"
irb(main):002:0> ("a".."aa").max
=> "z"
irb(main):003:0> puts ("a".."aa").to_a
a
b
c
d
e
f
g
h
i
j
k
l
m
n
o
p
q
r
s
t
u
v
w
x
y
z
aa
=> nil
There is no optimization that works for all and I guess that's the
reason why Matz did not bother to provide Range#max and Enumerable#max
is used instead. And this has necessarily O(n). After all: if you
are smart enough to use Ruby then you are probably also smart enough
to not use #max on an integer range. :-)
Kind regards
robert