Shuffle the deck using PowerShell


Sunny Chakraborty (B|T), started a page about top 12 things on his mind and since the last one looked a little easy I took a shot at it. 

12. Better Get-Random for small ranges (0-1000). Test for randomness of Get-Random.

Oh boy! was I wrong. What started as an exercise to generate small random sets led me around Wikipedia pages and finally showed me the Fisher-Yates Shuffle.

This was my first solution. And it absolutely sucks, generates loads of zeros and the reason why this happens is not due to the lack of the randomness of the running ticks but the fact that we modulus the result with 1000 to get the value into our range of interest. The basic problem with this is that we can fix it but; at a cost to speed and we may also need a cache the intermediate states to guarantee uniqueness in the set.

Function Get-SmallRandom
{
$procArch = $env:PROCESSOR_ARCHITECTURE
if($env:PROCESSOR_ARCHITECTURE -match “\d{2}$”){$procArch = $Matches[0]}
if($procArch -eq 64){
[Int](((Get-Date).Second * (Get-Date).Millisecond * (Get-Date).Ticks) / ([Int64]::MaxValue + 1))
}elseif($procArch -eq 32){
[Int]((((Get-Date).Ticks/(Get-Date).Millisecond)/([Int32]::MaxValue + 1.0))/1000)
}else{
[Int]((((Get-Date).Ticks/(Get-Date).Millisecond)/([Int32]::MaxValue + 1.0))/1000)
}
}

$a = 1..1000 | %{Get-SmallRandom}
$b = 1..1000 | %{Get-SmallRandom}
Compare-Object -ReferenceObject $a -DifferenceObject $b -ExcludeDifferent

Then it struck me that I may have approached the problem in a wrong direction. Given a set of 1000 numbers, how do I shuffle the set in an unbiased way so that it has the appearance of a randomly generated set? Cool, so how the hell do I do it; the obvious solution was to pick two random numbers less than size of the array the swap the numbers. But, I was not sure if this was such a good idea and started looking if there were any algorithms that did this and surely there is, the ‘Fisher Yates shuffle’. It is easy to implement and works great. So, here is my crack at it:

Function Get-ShuffledArray
{
param(
[Array]$gnArr
)
$len = $gnArr.Length;
while($len)
{
$i = Get-Random ($len --);
$tmp = $gnArr[$len];
$gnArr[$len] = $gnArr[$i];
$gnArr[$i] = $tmp;
}
return $gnArr
}

Not sure if this is an acceptable solution for what Sunny was looking for but, it was a wonderful learning experience. As always, working with PowerShell is fun.

Advertisements
About

By profession, I’m a SQL Server Database Administrator. I love to poke my nose into different corners and see how stuff looks in there. I keep looking for new things to do as my mind refuses to settle on one topic.

Tagged with: , , , , ,
Posted in Fun-Stuff, PowerShell

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: