range max

  • Thread starter Marek Kasperkiewicz
  • Start date
M

Marek Kasperkiewicz

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?
 
M

Morton Goldberg

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?

I'm afraid that's the way the Enumerable mixin works.

There is an old saying: if hitting yourself on the head with hammer
hurts, just stop. I think that applies in this case.

Regards, Morton
 
B

Brian Adkins

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
 
M

Marek Kasperkiewicz

Morton said:
I'm afraid that's the way the Enumerable mixin works.

There is an old saying: if hitting yourself on the head with hammer
hurts, just stop. I think that applies in this case.

Regards, Morton


thanks Morton,
I thought ruby supposed to be better than Perl and Python combined, but
I can see that's not the case yet.
 
M

mortee

Marek said:
thanks Morton,
I thought ruby supposed to be better than Perl and Python combined, but
I can see that's not the case yet.

You think this has anything to do with the quality of the language?...

mortee
 
B

Brian Adkins

thanks Morton,
I thought ruby supposed to be better than Perl and Python combined, but
I can see that's not the case yet.

Congratulations, you found the Achilles heel of Ruby! We try to keep
it a secret, but the dreaded (1..N).max issue will undoubtedly keep
Ruby from realizing its true potential. From what I can tell from your
postings, I'd say you'll probably prefer Perl over Python - best
wishes.
 
A

ara.t.howard

thanks Morton,
I thought ruby supposed to be better than Perl and Python combined,
but
I can see that's not the case yet.

cfp:~ > cat a.rb
class Lang < String
class ::NilClass
def succ() Lang('perl') end
end

def succ
Lang(
case self
when /perl/i then 'python'
when /python/i then 'ruby'
else super
end
)
end

def <=> other
case other
when /ruby/i then match('ruby') ? 0 : -1
else super
end
end
end
def Lang(*a, &b) Lang.new(*a, &b) end


language = nil

list = [] and 3.times{ list << list.last.succ }

p list

p list.max, list.reverse.max, list.sort_by{ rand }.max


cfp:~ > ruby a.rb
["perl", "python", "ruby"]
"ruby"
"ruby"
"ruby"


a @ http://codeforpeople.com/
 
J

Joel VanderWerf

ara.t.howard said:
class Lang < String
class ::NilClass
def succ() Lang('perl') end
end

def succ
Lang(
case self
when /perl/i then 'python'
when /python/i then 'ruby'
else super
end
)
end ...
end
def Lang(*a, &b) Lang.new(*a, &b) end

nil.succ.succ.succ.succ
=> "rubz"


Is this the new name for ruby 2.0, instead of rite?

Well, I have to say it kinda rubz off on you after a while.
 
Y

Yossef Mendelssohn

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

Robert Klemme

2007/10/12 said:
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
 
B

Brian Adkins

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

Actually, what you want is simply N. It's a nonsensical request from a
troll. Using max, end, last, etc. to find the end of the range is
ridiculous since you must know the end of the range to define the
range!
 
M

mortee

Brian said:
Actually, what you want is simply N. It's a nonsensical request from a
troll. Using max, end, last, etc. to find the end of the range is
ridiculous since you must know the end of the range to define the
range!

Ehhh... it's actually quite probable that the OP was indeed just insult
- however, you all seem to assume that the same person provides both the
range and wants to know its max.

If e.g. you write a method, which accepts various types of arguments,
then you can't know in advance if it'll be a range, array or something
else. So you have to use #max - and then one might expect that a range
(however big the span is) can compute it in constant time.

So the OP had *some* validity, while this still doesn't have anything to
do with the quality of the language itself. Just one spot where the it
might possibly be enhanced a bit.

mortee
 
A

ara.t.howard

Actually, what you want is simply N. It's a nonsensical request from a
troll. Using max, end, last, etc. to find the end of the range is
ridiculous since you must know the end of the range to define the
range!

that is not true. any object can be used in a range in ruby. it
only must respond to #succ. it's quite possible to declare classes
that worked like so

class TimeOfDay
end

noon_today = TimeOfDay 12, :today
noon_morrow = TimeOfDay 12, :tomorrow

noon_to_noon = noon_today ... noon_tomorrow

p noon_to_noon.max #=> TimeOfDay< @hour=24, @minute=0, @second=0 >

in other words to construct a cycle or other sequence using a range.
and, more simply

-1 .. -4

while quite valid, requires some thought as to which end is the
maximum. with pure numbers you'd say -1 (the first) but, if those
were like so

Depth(-1) .. Depth(-4)

that the Depth class semantics may dictate that Depth(-4) is in fact
the max.

regards.

a @ http://codeforpeople.com/
 
B

Brian Adkins

Ehhh... it's actually quite probable that the OP was indeed just insult
- however, you all seem to assume that the same person provides both the
range and wants to know its max.

I think you're assuming we're assuming :) Rather than put words into
the OP's mouth with respect to the scope of the range problem he's
allegedly trying to solve, I was referring specifically to an integer
range problem only - can't speak for everyone though.

With respect to an integer range, a combination of Range#end and
Range#exclude_end?
 
B

Brian Adkins

that is not true. any object can be used in a range in ruby. it
only must respond to #succ. it's quite possible to declare classes
that worked like so

I'm not unfamiliar with the domain of the Range class. Let's not get
ridiculous here; I was referring specifically to integer ranges.
Nothing unambiguates like code, eh? :)

class Range
def max_int
raise 'invalid range' if self.end < self.begin
self.end - (self.exclude_end? ? 1 : 0)
end
end
 
B

Brian Adkins

0 ... 1

we know that max != 0, so

Wrong. (0...1).max_int -> 0 (see code in other post)
max = 0.9?
max = 0.99?
max = 0.999?
max = 0.9999?

What the heck are you talking about? Do you really think that 0.9 or
0.99 is in the range (0...1) ?
 
A

ara.t.howard

Wrong. (0...1).max_int -> 0 (see code in other post)

you code does not return the max, it returns the 'end', and
incorrectly in some cases.

any range/interval whose end > start *must* have size > 0. therefore
the max cannot == start. i think you are confusing the concept of
sequence with that of a range

http://en.wikipedia.org/wiki/Sequence # sequence
http://en.wikipedia.org/wiki/Interval_(mathematics) # range

there is *no* constraint on ruby ranges to be either - one may use
the range to represent either. if one uses it to represent an
interval the, with an open ended (... vs ..) range there is no way to
compute the max. this is a very useful property because you can use
it to do things like

f = 0.42

r = 0 ... 1

if f > r.start and f < r.end

...

so, if we are talking general purpose methods, which the OP was,
Range#max cannot be written to be general purpose, even for integer
'ranges'
What the heck are you talking about? Do you really think that 0.9 or
0.99 is in the range (0...1) ?

yes. but it is not in the integer sequence.

regards.

a @ http://codeforpeople.com/
 
B

Brian Adkins

I'm not unfamiliar with the domain of the Range class. Let's not get
ridiculous here; I was referring specifically to integer ranges.
Nothing unambiguates like code, eh? :)

class Range
def max_int
raise 'invalid range' if self.end < self.begin
self.end - (self.exclude_end? ? 1 : 0)
end
end

Actually, I think the following would be better for those rare people
who find themselves frequently wondering what the largest int in a
range is, and would prefer O(1) instead of O(n):

class Range
alias orig_max max
def max
if ( self.begin.kind_of?(Integer) &&
self.end.kind_of?(Integer) &&
self.begin <= self.end )
self.exclude_end? ? self.end - 1 : self.end
else
orig_max
end
end
end

Now if someone can just come up with a real world example (i.e.
currently existing code in production) of Ruby code that actually
requires this, I'll be amazed. :)
 

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
474,269
Messages
2,571,348
Members
48,026
Latest member
ArnulfoCat

Latest Threads

Top