[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Re: sorting by rand?

seebs

4/30/2007 2:29:00 AM

In message <40D2708E-0D0C-42E4-82B3-E31D93481880@mac.com>, Gary Wright writes:
>
>On Apr 29, 2007, at 10:01 PM, Peter Seebach wrote:
>> So, two vaguely related questions:
>> 1. Is there a reasonably sane way to do this, should I ever find
>> myself wanting one?
>
>Short answer: array.sort_by { rand }
>
>Longer answer: http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/...
>talk/168963

Well, okay. It works in practice. Is it guaranteed to work, and is
it actually reasonable to expect the output to be randomly shuffled?

Just for comparison, I tried:

l = a.length
a.each_index { |x| a[x] = a[rand(l)] }

I'm pretty sure I got the generic shuffle algorithm right (Knuth FTW),
and if so, it produces quality random results in about 1/4 the time.

-s

5 Answers

Gary Wright

4/30/2007 2:45:00 AM

0


On Apr 29, 2007, at 10:28 PM, Peter Seebach wrote:

> l = a.length
> a.each_index { |x| a[x] = a[rand(l)] }

You are trashing your original array.

irb(main):001:0> a = [1,2,3,4]
=> [1, 2, 3, 4]
irb(main):002:0> l = a.length
=> 4
irb(main):003:0> a.each_index { |x| a[x] = a[rand(l)] }
=> [3, 3, 3, 4]




Rick DeNatale

4/30/2007 2:46:00 AM

0

On 4/29/07, Peter Seebach <seebs@seebs.net> wrote:
> In message <40D2708E-0D0C-42E4-82B3-E31D93481880@mac.com>, Gary Wright writes:
> >
> >On Apr 29, 2007, at 10:01 PM, Peter Seebach wrote:
> >> So, two vaguely related questions:
> >> 1. Is there a reasonably sane way to do this, should I ever find
> >> myself wanting one?
> >
> >Short answer: array.sort_by { rand }
> >
> >Longer answer: http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/...
> >talk/168963
>
> Well, okay. It works in practice. Is it guaranteed to work, and is
> it actually reasonable to expect the output to be randomly shuffled?

See my longer explanation of sort_by which crossed in the e-mail.

> Just for comparison, I tried:
>
> l = a.length
> a.each_index { |x| a[x] = a[rand(l)] }
>
> I'm pretty sure I got the generic shuffle algorithm right (Knuth FTW),
> and if so, it produces quality random results in about 1/4 the time.

Looks suspicious to me, you are replacing each element of x in turn
with a randomly selected element, which means that you are likely to
end up with a different set of elements in the end. One of the
requirements of shuffling an array would seem to be that

shuffle(a).sort == a.sort

Something like:

a.each_index {|x| y=rand; a[x], a[y] = a[y], a[x]}

would seem to be a better approach, but a.sort_by {rand} does the same
thing more concisely.


--
Rick DeNatale

My blog on Ruby
http://talklikeaduck.denh...

Dan Zwell

4/30/2007 2:55:00 AM

0

Peter Seebach wrote:
> l = a.length
> a.each_index { |x| a[x] = a[rand(l)] }
>
> I'm pretty sure I got the generic shuffle algorithm right (Knuth FTW),
> and if so, it produces quality random results in about 1/4 the time.
>
> -s
>
>

The above probably has a typo or something.

This one's from Cormen, Leiserson, Rivest, and Stein. It swaps each
element with a random element in the rest of the list (allowing it to be
swapped with itself sometimes). I don't have the book in front of me,
but I think it's something like:

def randomize!(ary)
for i in 0...(ary.length)
j = i+rand(ary.length - i)
# swap ary[i] and ary[j]
tmp = ary[i]
ary[i] = ary[j]
ary[j] = tmp
end
ary
end

I think I can prove that it's a valid sort, but I don't trust my own
logic that much. I tested it with 1000 items and it seemed to have the
right number of each item.

>> a = [0, 1, 2, 3, 4]
=> [0, 1, 2, 3, 4]
>> randomized = []
=> []
>> 1000.times do randomized << randomize!(a.dup)
>> end
=> 1000
>> count = 0
=> 0
>> randomized.each {|ary| count += 1 if ary == [3, 1, 2, 0, 4]}
>> count
=> 8


So for one of the 120 permutations of [0, 1, 2, 3, 4], I counted the
occurrences of one of them. There were 8. On average, if there are 120
permutations, there will be 8 of each:

>> 1000/120
=> 8

Good enough for me, unless I was just really lucky. That happens with
random numbers, you know.

Dan

Marcin Raczkowski

4/30/2007 8:28:00 AM

0

On Monday 30 April 2007 02:55, Dan Zwell wrote:
> > l = a.length
> > a.each_index { |x| a[x] = a[rand(l)] }
> >

a.each_index { |x| r= rand(l); a[x], a[r] = a[r], a[x] }

--
Marcin Raczkowski
---
Friends teach what you should know
Enemies Teach what you have to know

Dan Zwell

4/30/2007 3:56:00 PM

0

Marcin Raczkowski wrote:
> On Monday 30 April 2007 02:55, Dan Zwell wrote:
>>> l = a.length
>>> a.each_index { |x| a[x] = a[rand(l)] }
>>>
>
> a.each_index { |x| r= rand(l); a[x], a[r] = a[r], a[x] }
>

I forgot you could do that. No wonder arrays don't have a swap method!