1
$CustomObjects = Get-Random -Count 7 -InputObject @(0..300) | ForEach-Object {$i = 0} {
    [PSCustomObject]@{
        id = ($i++)
        value = $_
    }
}

$min, $max = & {$Args[0].Minimum, $Args[0].Maximum} ($CustomObjects | ForEach-Object value | Measure-Object -Minimum -Maximum)

$CustomObjects | Format-Table id, value -RepeatHeader
$CustomObjects | Where-Object {$_.value -eq $min} | Format-Table id, value 
$CustomObjects | Where-Object {$_.value -eq $max} | Format-Table id, value

Are there more interesting options for finding the minimum / maximum?

2 Answers2

2

We could come up with a long list of valid PowerShell statements that all look slightly different and would yield the same result, but there's basically 2 ways:

  • Sorting
  • Keeping count

Obtaining min/max through sorting is exactly what it sounds like:

$min,$max = @($CustomObjects |Sort Value)[0,-1].Value
# or 
$min,$max = @($CustomObjects.Value |Sort)[0,-1]

Very succinct, easy to express - but might turn out to be slow on large collections

Obtaining min/max through keeping count is exactly what Measure-Object does:

$min,$max = [int]::MaxValue,[int]::MinValue
$CustomObjects |ForEach-Object {
  $min = [Math]::Min($_.Value, $min)
  $max = [Math]::Max($_.Value, $max)
}

Not as fancy, but faster for large collections

Mathias R. Jessen
  • 157,619
  • 12
  • 148
  • 206
1

Mathias R. Jessen's helpful answer shows elegant - but potentially wasteful in terms of memory - solutions (Sort-Object of necessity needs to collect all input objects in memory so as to be able to determine the sort order).

Your own, Measure-Object-based approach takes advantage of the memory-throttling property of the pipeline.

Due to use of PowerShell's pipeline, both approaches are likely to be slow, however - see this answer for a discussion.

A simple optimization of your approach is to make the ForEach-Object value pipeline segment unnecessary by passing -Property value to Measure-Object:

$CustomObjects | Measure-Object -Property value -Minimum -Maximum

The Microsoft.PowerShell.Commands.GenericMeasureInfo returned by this command has .Minimum and .Maximum properties, so there's no strict reason to create separate $min and $max variables, but if you wanted to:

$measureResult = $CustomObjects | Measure-Object -Property value -Minimum -Maximum
$min, $max = $measureResult.Minimum, $measureResult.Maximum

If you'd rather not create an auxiliary variable, you can use the following, which uses the .ForEach() array method:

$min, $max = ($CustomObjects | Measure-Object -Property value -Minimum -Maximum).
                ForEach({ $_.Minimum, $_.Maximum })
mklement0
  • 382,024
  • 64
  • 607
  • 775