From f31b33863ce1cad9e4d85d5d3a015bcc7c20f71e Mon Sep 17 00:00:00 2001 From: Gaurav Kamath Date: Fri, 1 Mar 2019 04:11:37 -0800 Subject: [PATCH] Refactor Shuffle in Get-Random to save a full iteration of the objects. (#8969) --- .../commands/utility/GetRandomCommand.cs | 16 ++-- .../Get-Random.Tests.ps1 | 86 ++++++++++--------- 2 files changed, 49 insertions(+), 53 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetRandomCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetRandomCommand.cs index 162fee1b17..4bb98b8bad 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetRandomCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetRandomCommand.cs @@ -520,23 +520,17 @@ namespace Microsoft.PowerShell.Commands int n = _chosenListItems.Count; for (int i = 0; i < n; i++) { - // randomly choose an item to go into the i-th position + // randomly choose j from [i...n) int j = this.Generator.Next(i, n); - // swap j-th item into i-th position + this.WriteObject(_chosenListItems[j]); + + // remove the output object from consideration in the next iteration. if (i != j) { - object tmp = _chosenListItems[i]; - _chosenListItems[i] = _chosenListItems[j]; - _chosenListItems[j] = tmp; + _chosenListItems[j] = _chosenListItems[i]; } } - - // output all items - foreach (object chosenItem in _chosenListItems) - { - this.WriteObject(chosenItem); - } } } diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/Get-Random.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/Get-Random.Tests.ps1 index e18cbe1a8a..d47280ca76 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/Get-Random.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/Get-Random.Tests.ps1 @@ -85,84 +85,86 @@ Describe "Get-Random DRT Unit Tests" -Tags "CI" { Describe "Get-Random" -Tags "CI" { It "Should return a random number greater than -1 " { - Get-Random | Should -BeGreaterThan -1 + Get-Random | Should -BeGreaterThan -1 } It "Should return a random number less than 100 " { - Get-Random -Maximum 100 | Should -BeLessThan 100 - Get-Random -Maximum 100 | Should -BeGreaterThan -1 + Get-Random -Maximum 100 | Should -BeLessThan 100 + Get-Random -Maximum 100 | Should -BeGreaterThan -1 } It "Should return a random number less than 100 and greater than -100 " { - $randomNumber = Get-Random -Minimum -100 -Maximum 100 - $randomNumber | Should -BeLessThan 100 - $randomNumber | Should -BeGreaterThan -101 + $randomNumber = Get-Random -Minimum -100 -Maximum 100 + $randomNumber | Should -BeLessThan 100 + $randomNumber | Should -BeGreaterThan -101 } It "Should return a random number less than 20.93 and greater than 10.7 " { - $randomNumber = Get-Random -Minimum 10.7 -Maximum 20.93 - $randomNumber | Should -BeLessThan 20.93 - $randomNumber | Should -BeGreaterThan 10.7 + $randomNumber = Get-Random -Minimum 10.7 -Maximum 20.93 + $randomNumber | Should -BeLessThan 20.93 + $randomNumber | Should -BeGreaterThan 10.7 } It "Should return same number for both Get-Random when switch SetSeed is used " { - $firstRandomNumber = Get-Random -Maximum 100 -SetSeed 23 - $secondRandomNumber = Get-Random -Maximum 100 -SetSeed 23 - $firstRandomNumber | Should -Be $secondRandomNumber + $firstRandomNumber = Get-Random -Maximum 100 -SetSeed 23 + $secondRandomNumber = Get-Random -Maximum 100 -SetSeed 23 + $firstRandomNumber | Should -Be $secondRandomNumber } It "Should return a number from 1,2,3,5,8,13 " { - $randomNumber = Get-Random -InputObject 1, 2, 3, 5, 8, 13 - $randomNumber | Should -Be (1 -or 2 -or 3 -or 5 -or 8 -or 13) + $randomNumber = Get-Random -InputObject 1, 2, 3, 5, 8, 13 + $randomNumber | Should -Be (1 -or 2 -or 3 -or 5 -or 8 -or 13) } It "Should return an array " { - $randomNumber = Get-Random -InputObject 1, 2, 3, 5, 8, 13 -Count 3 - $randomNumber.Count | Should -Be 3 - ,$randomNumber | Should -BeOfType "System.Array" + $randomNumber = Get-Random -InputObject 1, 2, 3, 5, 8, 13 -Count 3 + $randomNumber.Count | Should -Be 3 + ,$randomNumber | Should -BeOfType "System.Array" } It "Should return three random numbers for array of 1,2,3,5,8,13 " { - $randomNumber = Get-Random -InputObject 1, 2, 3, 5, 8, 13 -Count 3 - $randomNumber[0] | Should -Be (1 -or 2 -or 3 -or 5 -or 8 -or 13) - $randomNumber[1] | Should -Be (1 -or 2 -or 3 -or 5 -or 8 -or 13) - $randomNumber[2] | Should -Be (1 -or 2 -or 3 -or 5 -or 8 -or 13) - $randomNumber[3] | Should -BeNullOrEmpty + $randomNumber = Get-Random -InputObject 1, 2, 3, 5, 8, 13 -Count 3 + $randomNumber.Count | Should -Be 3 + $randomNumber[0] | Should -Be (1 -or 2 -or 3 -or 5 -or 8 -or 13) + $randomNumber[1] | Should -Be (1 -or 2 -or 3 -or 5 -or 8 -or 13) + $randomNumber[2] | Should -Be (1 -or 2 -or 3 -or 5 -or 8 -or 13) + $randomNumber[3] | Should -BeNullOrEmpty } It "Should return all the numbers for array of 1,2,3,5,8,13 in no particular order" { - $randomNumber = Get-Random -InputObject 1, 2, 3, 5, 8, 13 -Count ([int]::MaxValue) - $randomNumber[0] | Should -Be (1 -or 2 -or 3 -or 5 -or 8 -or 13) - $randomNumber[1] | Should -Be (1 -or 2 -or 3 -or 5 -or 8 -or 13) - $randomNumber[2] | Should -Be (1 -or 2 -or 3 -or 5 -or 8 -or 13) - $randomNumber[3] | Should -Be (1 -or 2 -or 3 -or 5 -or 8 -or 13) - $randomNumber[4] | Should -Be (1 -or 2 -or 3 -or 5 -or 8 -or 13) - $randomNumber[5] | Should -Be (1 -or 2 -or 3 -or 5 -or 8 -or 13) - $randomNumber[6] | Should -BeNullOrEmpty + $randomNumber = Get-Random -InputObject 1, 2, 3, 5, 8, 13 -Count ([int]::MaxValue) + $randomNumber.Count | Should -Be 6 + $randomNumber[0] | Should -Be (1 -or 2 -or 3 -or 5 -or 8 -or 13) + $randomNumber[1] | Should -Be (1 -or 2 -or 3 -or 5 -or 8 -or 13) + $randomNumber[2] | Should -Be (1 -or 2 -or 3 -or 5 -or 8 -or 13) + $randomNumber[3] | Should -Be (1 -or 2 -or 3 -or 5 -or 8 -or 13) + $randomNumber[4] | Should -Be (1 -or 2 -or 3 -or 5 -or 8 -or 13) + $randomNumber[5] | Should -Be (1 -or 2 -or 3 -or 5 -or 8 -or 13) + $randomNumber[6] | Should -BeNullOrEmpty } It "Should return for a string collection " { - $randomNumber = Get-Random -InputObject "red", "yellow", "blue" - $randomNumber | Should -Be ("red" -or "yellow" -or "blue") + $randomNumber = Get-Random -InputObject "red", "yellow", "blue" + $randomNumber | Should -Be ("red" -or "yellow" -or "blue") } It "Should return a number for hexadecimal " { - $randomNumber = Get-Random 0x07FFFFFFFFF - $randomNumber | Should -BeLessThan 549755813887 - $randomNumber | Should -BeGreaterThan 0 + $randomNumber = Get-Random 0x07FFFFFFFFF + $randomNumber | Should -BeLessThan 549755813887 + $randomNumber | Should -BeGreaterThan 0 } It "Should return false, check two random numbers are not equal when not using the SetSeed switch " { - $firstRandomNumber = Get-Random - $secondRandomNumber = Get-Random - $firstRandomNumber | Should -Not -Be $secondRandomNumber + $firstRandomNumber = Get-Random + $secondRandomNumber = Get-Random + $firstRandomNumber | Should -Not -Be $secondRandomNumber } It "Should return the same number for hexadecimal number and regular number when the switch SetSeed it used " { - $firstRandomNumber = Get-Random 0x07FFFFFFFF -SetSeed 20 - $secondRandomNumber = Get-Random 34359738367 -SetSeed 20 - $firstRandomNumber | Should -Be @secondRandomNumber + $firstRandomNumber = Get-Random 0x07FFFFFFFF -SetSeed 20 + $secondRandomNumber = Get-Random 34359738367 -SetSeed 20 + $firstRandomNumber | Should -Be @secondRandomNumber } It "Should throw an error because the hexadecimal number is to large " { - { Get-Random 0x07FFFFFFFFFFFFFFFF } | Should -Throw "Value was either too large or too small for a UInt32" + { Get-Random 0x07FFFFFFFFFFFFFFFF } | Should -Throw "Value was either too large or too small for a UInt32" } }