# encoding: ascii # api: powershell # title: Select-Random # description: Select a user-defined number of random elements from the collection … which can be passed as a parameter or input via the pipeline. An improvement over http://www.powershellcentral.com/scripts/60 which allows you to select more than one item, but offers the option to collect the pipeline into RAM to trade speed for memory use (replaces 81 and 83). # version: 2.2 # type: script # author: Joel Bennett # license: CC0 # x-poshcode-id: 118 # x-archived: 2013-05-05T10:57:09 # x-published: 2008-01-20T21:10:00 # # # --------------------------------------------------------------------------- ### # --------------------------------------------------------------------------- param([int]$count=1, [switch]$collectionMethod, [array]$inputObject=$null) BEGIN { if ($args -eq '-?') { @" Usage: Select-Random [[-Count] ] [-inputObject] (from pipeline) [-?] Parameters: -Count : The number of elements to select. -inputObject : The collection from which to select a random element. -collectionMethod : Collect the pipeline input instead of using reservoir -? : Display this usage information and exit Examples: PS> $arr = 1..5; Select-Random $arr PS> 1..10 | Select-Random -Count 2 "@ exit } else { $rand = new-object Random if ($inputObject) { # Write-Output $inputObject | &($MyInvocation.InvocationName) -Count $count } elseif($collectionMethod) { Write-Verbose "Collecting from the pipeline " [Collections.ArrayList]$inputObject = new-object Collections.ArrayList } else { $seen = 0 $selected = new-object object[] $count } } } PROCESS { if($_) { if($collectionMethod) { $inputObject.Add($_) | out-null } else { $seen++ if($seen -lt $count) { $selected[$seen-1] = $_ } ## For each input element $n there is a $count/$n chance that it becomes part of the result. elseif($rand.NextDouble() -lt ($count/$seen)) { ## For the ones previously selected, there's a 1/$n chance of it being replaced $selected[$rand.Next(0,$count)] = $_ } } } } END { if (-not $inputObject) { ## DO ONCE: (only on the re-invoke, not when using -inputObject) Write-Verbose "Selected $count of $seen elements." Write-Output $selected # foreach($el in $selected) { Write-Output $el } } else { Write-Verbose ("{0} elements, selecting {1}." -f $inputObject.Count, $Count) foreach($i in 1..$Count) { Write-Output $inputObject[$rand.Next(0,$inputObject.Count)] } } }