Random range

No Enumerable#size. Try:

module Enumerable

Return a random element, or nil if empty.

def rand
i = 1
ret = nil
each do |el|
if Kernel.rand(i) == 0
ret = el
end
i += 1
end
return ret
end
end

Umm I don’t think that is a uniform distribution, not to mention the

It is uniform…

fact that you don’t break out of the each if it succeeds.

… precisely because he doesn’t break out of the each if it succeeds.

S(i): element i is taken in ret = el (i.e. Kernel.rand(i) == 0)
AND: intersection
PI: big PI (product)
N: number of elements in the Enumerable (if infinite, rand would never
return)

P(ret == el(i) at the end) = P(S(i) AND (for all N >= j > i NOT S(j)))
== { they’re independent if we ignore the fact that this is a PRNG } ==
= P(S(i)) * P(for all j > i NOT (S(j))) == { S(j) and S(j+1) indep. }

= 1/i * PI(1-P(S(j)), j = i+1 … N) =
= 1/i * (1-1/(i+1)) * (1-1/(i+2)) * … * (1-1/(N)) =
= 1/i * i/(i+1) * (i+1)/(i+2) * … * (N-1)/N =
= 1/i * i / N = 1 / N

or, for those who (like me) have no idea what the above means:

>> 10000.times{b[a.rand]+=1}

=> 10000
>> 10000.times{b[a.rand]+=1}
=> 10000
>> b
=> [2055, 1959, 1934, 2002, 1983, 1931, 2005, 2050, 2057, 2024]

looks good to me!

–Mark

···

On Mar 7, 2004, at 3:51 AM, Mauricio Fernández wrote:

On Sun, Mar 07, 2004 at 04:49:39PM +0900, Charles Comstock wrote:


Running Debian GNU/Linux Sid (unstable)
batsman dot geo at yahoo dot com

Netscape is not a newsreader, and probably never shall be.
– Tom Christiansen

Mark Hubbart discord@mac.com wrote in message news:B80C2894-6FCA-11D8-B2B9-000502FDD5CC@mac.com

It’s not redefining rand to take more varied arguments that’s a bad
thing, it’s defining it for Array#rand that’s a Bad Idea™, IMHO.
Kernel is included in Object so that you can access it’s methods
easily
within other objects. Redefining it in a subclass could potentially
break lots of code. For example, I often do this:

class Array
def randomize()
sort{rand(2)-0.5}
end
end

… and defining an Array#rand would break this.

You must not be very fond of IO#gets, Thread#exit, Dir::open, or
Proc#binding :slight_smile: Which is to say – there are cases where Kernel
methods we use without a receiver do get redefined for specialized
purposes.

point taken :slight_smile: Still, with IO#gets and Thread#exit (I admit I haven’t
used the others), the kernel methods were redefined so that they would
make more sense in the context. My beef with Array#rand is that it
redefines it to do something very different from what the Kernel
method does. Kernel.rand generates a random number within parameters,
the proposed Array.rand would select a random element from a list.
Maybe it’s only a distinction I make in my head :slight_smile:

However, while it’s moot anyway because of my fatal
Enumerable#size flaw, my snippet was really just to show the behavior
we were discussing on IRC.

Just because it can’t be added to Enumerable, doesn’t mean it should be
nixed. I would certainly still want it in Array, personally. I just
think it should have a different name. :slight_smile:

No endorsement of reckless endangerment of
Kernel intended :slight_smile:

:slight_smile:

BTW, the reason I’m fairly strong against Array#rand is because I added
that exact method into my personal “utils” library a while back, and
suddenly a lot of my scripts started failing. It took me a while to
figure out where the problem was. :slight_smile:

–Mark

First off let me apologise if I double post.
My Browser crashed on the first attempt and I dont
remember if I hit submit or not.

What about…
Or, what would the dangers be with,

class Range
def random
r = self.to_a
r[ rand(r.size) ]
end
end

(5…10).random

class Array
def random
self[ rand(size) ]
end
end

[2,4,6,8].random

Or, I guess they could be named: a_rand, r_rand

···

On Mar 6, 2004, at 1:17 PM, David A. Black wrote:

On Sun, 7 Mar 2004, Mark Hubbart wrote:

What about this…
Or, what would the dangers be?

class Range
def random
r = self.to_a
r[ rand(r.size) ]
end
end

(5..10).random

yes but what happens when someone says
(1..1000000000).random
or how about even worse
(1.1 .. 2.56).random #<-- this definitely breaks it (infinite set)

For integers the best thing for Range would be
class Range
def pick
lower + rand(upper)
end
end

i’m pretty sure the range is wrong on that but the idea is there

But obviously that doesn’t work for anything else. The main problem
with pick/random over a range is without doing a to_a we actually don’t
know what the size of the range is, which is potentially pretty bad.
Not to mention when it’s over a floating range where you get infinite
numbers in between technically.

So I think what that means is we can add pick to array and hash, as well
as pick!, but not to enumerable. For the rand, I still think we should
modify it to take a numeric range. Other then that I don’t think we can
generalize it.

Charles Comstock