Get-RandFrom ( collection and/or pipeline )

Topics: Developer Forum, User Forum
Developer
Apr 13, 2007 at 7:33 PM
Honestly, I was surprised this wasn't in the commandlet, because it's such a cool feature ... but when I thought about adding it, I realized that it could be done as a function, and that I needed some practice, so I'm posting it here:

function Get-RandFrom([array]$collection) {
  begin
  {
    if ($collection.count -gt 0) { 
      $coll += $collection
    } else {
      $coll = @();
    }
  }
  process
  {
    $coll += $_;
  }
  end
  {
    if ($coll)
    {
      $coll[( Get-Random -Min 0 -Max ($coll.Count) )]
    }
  }
}

Basically what this lets you do is things like getting a random line from a random text file in the current folder:

ls *.txt | Get-RandFrom | Get-Content | Get-RandFrom

Obviously that's much easier to use and read than the alternative... presented here as a multi-line script because putting it in a single line requires calling Get-ChildItem and Get-Content twice ...

$files = ls *.txt
$lines = cat $files[(Get-Random -Min 0 -Max $files.Count)]
$lines[(Get-Random -Min 0 -Max $lines.Count)]

So ... I'm a little obsessive about my random quotes ;-)
Coordinator
Apr 14, 2007 at 4:16 AM
I like this. I would suggest a few changes. First this seems more like a "select" command than a "get" command. Second, we have been leaning towards doing more scripts than profile dot sourced functions in order to keep peoples profiles from getting too large. With that in mind, tell me what you think about this:

# ---------------------------------------------------------------------------
### <Script>
### <Author>
### Jaykul
### newsgroup.
### </Author>
### <Description>
### Selects a random element from the collection either passed as a parameter
### or input via the pipeline.
### </Description>
### <Usage>
### $arr = 1..5; Select-Random $arr
### 1..5 | Select-Random
### </Usage>
### </Script>
# ---------------------------------------------------------------------------
param([array]$Collection)
 
begin {
    $result = $Seed
    
    if ($args -eq '-?') {
        ''
        'Usage: Select-Random [[-Collection] <array>]'
        ''
        'Parameters:'
        '    -Collection : The collection from which to select a random entry.'
        '    -?          : Display this usage information'
        ''
        'Examples:'
        '    PS> $arr = 1..5; Select-Random $arr'
        '    PS> 1..5 | Select-Random'
        ''
        exit
    } 
 
    $coll = @()
    if ($collection.count -gt 0) { 
        $coll += $collection
    }
}
 
process {
    if ($_) {
        $coll += $_;
    }
}
 
end {
    if ($coll) {
        $randomIndex = Get-Random -Min 0 -Max ($coll.Count)
        $coll[$randomIndex]
    }
}
Developer
Apr 15, 2007 at 4:14 AM
That looks good to me, and works just as well, keeping my profile smaller makes sense to me ;)

But I must admit I'm now officially confused about when and why to use functions instead of scripts...
Coordinator
Apr 16, 2007 at 5:01 PM
With the 1.1 release we started to migrate towards providing scripts instead of dot sourced functions to lessen our impact on the user's global environment. Some functions and filters are probably still worth dot sourcing into a profile e.g. CD, DIR variants. At this point, if you think the function would get used a lot and/or it is very small (a few lines of script) then loading it via the profile is probably OK.
Coordinator
Apr 16, 2007 at 5:04 PM
BTW mind if I add this file to the Scripts dir of 1.1 tree. We should be able to get this into our 1.1.1 patch release. Of if you want to add it, go for it. Just keep in mind that it will need to be reverse integrated into the trunk.
Developer
Apr 16, 2007 at 11:04 PM

rkeithhill wrote:
BTW mind if I add this file to the Scripts dir of 1.1 tree. We should be able to get this into our 1.1.1 patch release. Of if you want to add it, go for it. Just keep in mind that it will need to be reverse integrated into the trunk.


Please go ahead ... I haven't got TFS figured out yet.