Pseudo-randomize an array in a consistent order

Does anyone know how to pseudo-randomize an array (eg with a seed) so
that you get the same order every time you do it?

thanks
max

···

--
Posted via http://www.ruby-forum.com/.

Max Williams <toastkid.williams@gmail.com> writes:

Does anyone know how to pseudo-randomize an array (eg with a seed) so
that you get the same order every time you do it?

Using a pseudo-random number generator, seeded with the same seed.

Another way would be to just use the seed to index the permutations of
the array, but you would need big seeds for non-small arrays...

···

--
__Pascal Bourguignon__

Hi --

···

On Thu, 3 Jul 2008, Max Williams wrote:

Does anyone know how to pseudo-randomize an array (eg with a seed) so
that you get the same order every time you do it?

Use Kernel#srand.

David

--
Rails training from David A. Black and Ruby Power and Light:
   Intro to Ruby on Rails July 21-24 Edison, NJ
   Advancing With Rails August 18-21 Edison, NJ
See http://www.rubypal.com for details and updates!

a.sort{ rand }

but I do not know about a seed.

Cheers
Robert

···

--
http://ruby-smalltalk.blogspot.com/

---
AALST (n.) One who changes his name to be further to the front
D.Adams; The Meaning of LIFF

Max Williams wrote:

Does anyone know how to pseudo-randomize an array (eg with a seed) so
that you get the same order every time you do it?

If I've understood the problem correctly, can't you set up a lookup
table for the array indices? You don't have to change the array itself.

The lookup table can be an array, e.g.

  t[0] = 1
  t[1] = 4
  t[2] = 2
  t[3] = 3
  t[4] = 0

Then if the original array is arr, instead of accessing arr[i] you'd
access arr[t[i]].

···

--
Posted via http://www.ruby-forum.com/\.

ruby19 has a Array#shuffle method:
irb(main):001:0> Kernel.srand(1); [1,2,3,4,5].shuffle
=> [2, 4, 1, 5, 3]
irb(main):002:0> Kernel.srand(1); [1,2,3,4,5].shuffle
=> [2, 4, 1, 5, 3]

···

On Jul 3, 4:56 pm, Max Williams <toastkid.willi...@gmail.com> wrote:

Does anyone know how to pseudo-randomize an array (eg with a seed) so
that you get the same order every time you do it?

Thanks guys

This is what i did in the meantime since asking (I monkey-patched
Array):

class Array

  def randomize(seed=nil)
   srand(seed) if seed
   self.sort{|a,b| rand <=> rand }
  end

  def randomize!(seed=nil)
   srand(seed) if seed
   self.sort!{|a,b| rand <=> rand }
  end

end

I'm worried though that using sort like this is a bit inefficient. The
array being sorted is around 3000 numbers (and not likely to exceed
5000) so maybe that's not too much of an issue. Is there a more
efficient way you can think of?

···

--
Posted via http://www.ruby-forum.com/.

a.sort{ rand }

Don't do that:

>> a = (1..5).to_a
=> [1, 2, 3, 4, 5]
>> a.sort { rand }
=> [5, 3, 1, 4, 2]
>> a.sort { rand }
=> [5, 3, 1, 4, 2]
>> a.sort { rand }
=> [5, 3, 1, 4, 2]

Use a.sort_by { rand } instead.

James Edward Gray II

···

On Jul 3, 2008, at 11:04 AM, Robert Dober wrote:

ThoML wrote:

···

On Jul 3, 4:56 pm, Max Williams <toastkid.willi...@gmail.com> wrote:

Does anyone know how to pseudo-randomize an array (eg with a seed) so
that you get the same order every time you do it?

ruby19 has a Array#shuffle method:
irb(main):001:0> Kernel.srand(1); [1,2,3,4,5].shuffle
=> [2, 4, 1, 5, 3]
irb(main):002:0> Kernel.srand(1); [1,2,3,4,5].shuffle
=> [2, 4, 1, 5, 3]

I'm only on 1.8.6 (and not likely to change soon since we'd want to do
all our work servers as well), but out of interest, do you know how
shuffle compares to .sort_by{rand} (thanks rob!) in terms of efficiency?

--
Posted via http://www.ruby-forum.com/\.

Hi --

···

On Fri, 4 Jul 2008, Max Williams wrote:

Thanks guys

This is what i did in the meantime since asking (I monkey-patched
Array):

class Array

def randomize(seed=nil)
  srand(seed) if seed
  self.sort{|a,b| rand <=> rand }
end

def randomize!(seed=nil)
  srand(seed) if seed
  self.sort!{|a,b| rand <=> rand }
end

end

I'm worried though that using sort like this is a bit inefficient. The
array being sorted is around 3000 numbers (and not likely to exceed
5000) so maybe that's not too much of an issue. Is there a more
efficient way you can think of?

I absolutely wouldn't worry about it, unless you actually notice any
slowness.

David

--
Rails training from David A. Black and Ruby Power and Light:
   Intro to Ruby on Rails July 21-24 Edison, NJ
   Advancing With Rails August 18-21 Edison, NJ
See http://www.rubypal.com for details and updates!

Oh, you meant to show this behavior. My bad.

James Edward Gray II

···

On Jul 3, 2008, at 11:08 AM, James Gray wrote:

On Jul 3, 2008, at 11:04 AM, Robert Dober wrote:

a.sort{ rand }

Don't do that:

>> a = (1..5).to_a
=> [1, 2, 3, 4, 5]
>> a.sort { rand }
=> [5, 3, 1, 4, 2]
>> a.sort { rand }
=> [5, 3, 1, 4, 2]
>> a.sort { rand }
=> [5, 3, 1, 4, 2]

Use sort_by{rand} and you'll call rand once per element (O(n)) rather than twice per comparison (O(n*log(n)))

-Rob

Rob Biedenharn http://agileconsultingllc.com
Rob@AgileConsultingLLC.com

···

On Jul 3, 2008, at 11:57 AM, Max Williams wrote:

Thanks guys

This is what i did in the meantime since asking (I monkey-patched
Array):

class Array

def randomize(seed=nil)
  srand(seed) if seed
  self.sort{|a,b| rand <=> rand }
end

def randomize!(seed=nil)
  srand(seed) if seed
  self.sort!{|a,b| rand <=> rand }
end

end

I'm worried though that using sort like this is a bit inefficient. The
array being sorted is around 3000 numbers (and not likely to exceed
5000) so maybe that's not too much of an issue. Is there a more
efficient way you can think of?

It looks like it should be faster for larger arrays. There are actually two
methods Array#shuffle! and Array#shuffle

Here's a Ruby translation of the C code:

class Array
  def shuffle!
      i = length - 1
      while (i > 0)
           j = rand(i)
           # Swap self[i] and self[j]
           # This might be more elegant using a parallel assignment, but
           # parallel assignment generates a temporary array, so this is
           # a little closer to the C code
           tmp = self[i]
           self[i] = self[j]
           self[j] = self[i]
           i -= 1
      end
      self
  end

  def shuffle
      self.dup.shuffle!
  end
end

So shuffle is O(n) whereas any sort is going to be O(>n)

···

On Thu, Jul 3, 2008 at 12:59 PM, Max Williams <toastkid.williams@gmail.com> wrote:

ThoML wrote:
> On Jul 3, 4:56 pm, Max Williams <toastkid.willi...@gmail.com> wrote:
>> Does anyone know how to pseudo-randomize an array (eg with a seed) so
>> that you get the same order every time you do it?
>
> ruby19 has a Array#shuffle method:
> irb(main):001:0> Kernel.srand(1); [1,2,3,4,5].shuffle
> => [2, 4, 1, 5, 3]
> irb(main):002:0> Kernel.srand(1); [1,2,3,4,5].shuffle
> => [2, 4, 1, 5, 3]

I'm only on 1.8.6 (and not likely to change soon since we'd want to do
all our work servers as well), but out of interest, do you know how
shuffle compares to .sort_by{rand} (thanks rob!) in terms of efficiency?

--
Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/

James you should know me better :wink: He does not want sort_by{ rand } he
explicitely asked for deterministic results, thus
   sort{ rand }.
But yet James is right of course, even if for the wrong reason here.
First of all you cannot set the seed, second of all it will not be
portable (jruby reverses for example, while ruby1.8 and ruby1.9 do the
same right now), and I guess that this is not guaranteed behavior at
all.

So after all I have to admit it was not my brightest idea to introduce
this "pattern" :wink: OTOH I had worse ideas.

Cheers
Robert

···

On Thu, Jul 3, 2008 at 6:08 PM, James Gray <james@grayproductions.net> wrote:

On Jul 3, 2008, at 11:04 AM, Robert Dober wrote:

a.sort{ rand }

Don't do that:

a = (1..5).to_a

=> [1, 2, 3, 4, 5]

a.sort { rand }

=> [5, 3, 1, 4, 2]

a.sort { rand }

=> [5, 3, 1, 4, 2]

a.sort { rand }

=> [5, 3, 1, 4, 2]

Use a.sort_by { rand } instead.

James Edward Gray II

--
http://ruby-smalltalk.blogspot.com/

---
AALST (n.) One who changes his name to be further to the front
D.Adams; The Meaning of LIFF

Hi Max,

How about a very small change:

class Array
  def randomize(seed=nil)
    srand(seed) if seed
    sort_by { rand }
    srand # re-seed random number generator
  end

  def randomize!(seed=nil)
    replace(randomize(seed))
  end
end

Because the seed used to generate random values (via Kernel#rand) is
global, if you switch it back, you'll (likely) affect random numbers
across your entire Ruby instance. I don't know if this will have any
effect on your current project, but should you ever integrate this
technique on another project, it could cause a problem.

Eric

···

On Jul 3, 11:57 am, Max Williams <toastkid.willi...@gmail.com> wrote:

This is what i did in the meantime since asking (I monkey-patched
Array):

class Array

def randomize(seed=nil)
srand(seed) if seed
self.sort{|a,b| rand <=> rand }
end

def randomize!(seed=nil)
srand(seed) if seed
self.sort!{|a,b| rand <=> rand }
end

end

====

LearnRuby.com offers Rails & Ruby HANDS-ON public & ON-SITE
workshops. Please visit http://LearnRuby.com for all the details.

I would suggest using sort_by { |a| rand }

Otherwise, you could trigger a pathological case if the algorithm depends
on the assumption that every comparison of any two elements will yield the
same results. (sort_by caches the values it generates, so that doesn't
happen.)

···

On 2008-07-03, Max Williams <toastkid.williams@gmail.com> wrote:

class Array

  def randomize(seed=nil)
   srand(seed) if seed
   self.sort{|a,b| rand <=> rand }
  end

--
Copyright 2008, all wrongs reversed. Peter Seebach / usenet-nospam@seebs.net
| Seebs.Net <-- lawsuits, religion, and funny pictures
Fair game (Scientology) - Wikipedia <-- get educated!

David A. Black wrote:

I absolutely wouldn't worry about it, unless you actually notice any
slowness.

Cool, if there's a problem i'll say David A. Black told me it would be
ok :slight_smile:

thanks everyone

···

--
Posted via http://www.ruby-forum.com/\.

Hi --

···

On Fri, 4 Jul 2008, James Gray wrote:

On Jul 3, 2008, at 11:08 AM, James Gray wrote:

On Jul 3, 2008, at 11:04 AM, Robert Dober wrote:

a.sort{ rand }

Don't do that:

>> a = (1..5).to_a
=> [1, 2, 3, 4, 5]
>> a.sort { rand }
=> [5, 3, 1, 4, 2]
>> a.sort { rand }
=> [5, 3, 1, 4, 2]
>> a.sort { rand }
=> [5, 3, 1, 4, 2]

Oh, you meant to show this behavior. My bad.

It's not really even pseudo-random, though -- it's just what you get
if you always say that a <=> b is > 0. [1,2,3,4,5].sort { 1 } does the
same thing. So every 5-element array will shuffle the same way, which
I don't think is what the OP wanted.

David

--
Rails training from David A. Black and Ruby Power and Light:
   Intro to Ruby on Rails July 21-24 Edison, NJ
   Advancing With Rails August 18-21 Edison, NJ
See http://www.rubypal.com for details and updates!

           # Swap self[i] and self[j]
           # This might be more elegant using a parallel assignment, but
           # parallel assignment generates a temporary array, so this is
           # a little closer to the C code
           tmp = self[i]
           self[i] = self[j]
           self[j] = self[i]

There's a typo here the line above should be self[j] = tmp

···

On Thu, Jul 3, 2008 at 1:44 PM, Rick DeNatale <rick.denatale@gmail.com> wrote:

           i -= 1
      end
      self
  end

  def shuffle
      self.dup.shuffle!
  end
end

So shuffle is O(n) whereas any sort is going to be O(>n)

--
Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/

--
Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/

Rick Denatale wrote:

class Array
  def shuffle!
      i = length - 1
      while (i > 0)
           j = rand(i)
           # Swap self[i] and self[j]
           # This might be more elegant using a parallel assignment, but
           # parallel assignment generates a temporary array, so this is
           # a little closer to the C code
           tmp = self[i]
           self[i] = self[j]
           self[j] = tmp
           i -= 1
      end
      self
  end

So shuffle is O(n) whereas any sort is going to be O(>n)

I'm still on 1.8.6, which doesn't have shuffle, but i'll use this
algorithm in my own randomize method, it's nice.

Eric, thanks for the suggestion about unseeding rand before returning,
good idea.

Thanks again, guys, great stuff.

···

--
Posted via http://www.ruby-forum.com/\.