MapReduceFilter.psm1

<#
 .Synopsis
  Perform functional-style operations on each element of a sequence or stream of objects in a Powershell pipeline
 
 .Description
  Apply the given ScriptBlock expression to each member of the pipelined InputObject.
 
 .Parameter Expression
  The anonymous (in-place) or named (as variable) single-argument lambda function to be applied to each InputObject element. This must have a single-argument parameter block.
 
 .Parameter InputObject
  The sequence or stream of Objects from the Powershell pipeline.
 
 .Example
   # Double each element of a list.
   @(1,2,3) | Convert-Map { param($it) 2 * $it }
   2
   4
   6
 
 .Example
   # First double each element of a list and then add 3 to each element of the new list.
   @(1,2,3) | Convert-Map { param($it) 2 * $it } | Convert-Map { param($doubled) $doubled + 3 }
   5
   7
   9
#>

function Convert-Map
{
    [cmdletbinding()]
    param (
        [Parameter(Mandatory)]
        [ValidateScript({ $_.Ast.ParamBlock.Parameters.Count -eq 1 })]
        [Scriptblock] $Expression,
 
        [Parameter(Mandatory = $true,
            ValueFromPipeline = $true)]
        [object[]] $InputObject
    )

    begin { if ( $InputObject ) { $Accumulator = $InputObject | % { &$Expression $_ } } else { $Accumulator = @() } }

    process { if ( $input ) { $Accumulator = $Accumulator + @( &$Expression $_ ) } }

    end { $Accumulator }
}

<#
 .Synopsis
  Perform functional-style folding or reducing operations on a sequence or stream of objects in a Powershell pipeline
 
 .Description
  Apply the given ScriptBlock expression to an accumulating value using each member of the pipelined InputObject.
 
 .Parameter Expression
  The anonymous (in-place) or named (as variable) single-argument lambda function to be applied to each InputObject element. This must have a double-argument parameter block.
 
 .Parameter InputObject
  The sequence or stream of Objects from the Powershell pipeline.
 
 .Example
   # Reduce a list to the sum of its elements.
   @(1,2,3) | Convert-Reduce { param($acc,$it) $acc + $it } -Accumulator 0
   6
 
 .Example
   # Apply a set of XSLT Transforms to an initial XML document, yielding the transformed XML after each transformation has been applied to the prior transformation
   @( $stylesheet1, $stylesheet2, $stylesheet3 ) | Convert-Reduce { param($acc,$it) Transform-Xslt -Output $acc -Stylesheet $it -Input $acc } -Accumulator $originalXml
#>
 
function Convert-Reduce
{
    [cmdletbinding()]
    param (
        [Parameter(Mandatory)]
        [ValidateScript({ $_.Ast.ParamBlock.Parameters.Count -eq 2 })]
        [Scriptblock] $Expression,
 
        [Parameter(Mandatory)]
        [Object] $Accumulator,

    [Parameter(Mandatory = $true,
        ValueFromPipeline = $true)]
        [object[]] $InputObject
    )

    begin { if ( $InputObject ) { $Accumulator = Convert-ListReduce $Expression -Accumulator $Accumulator -InputObject $InputObject } }

    process { $Accumulator = &$Expression $Accumulator $_ }

    end { $Accumulator }
}

function Convert-ListReduce
{
    [cmdletbinding()]
    param (
        [Parameter(Mandatory)]
        [ValidateScript({ $_.Ast.ParamBlock.Parameters.Count -eq 2 })]
        [Scriptblock] $Expression,
 
        [Parameter(Mandatory)]
        [Object] $Accumulator,

        [Parameter(Mandatory = $true,
        ValueFromPipeline = $true)]
        [object[]] $InputObject
    )

    begin { $InputObject | Convert-Reduce $Expression -Accumulator $Accumulator }
}

<#
 .Synopsis
  Perform functional-style operations on each pair of elements from two sequences or streams of objects in a Powershell pipeline
 
 .Description
  Apply the given ScriptBlock expression to each member of the pair of pipelined Objects.
 
 .Parameter Expression
  The anonymous (in-place) or named (as variable) single-argument lambda function to be applied to each InputObject element. This must have a single-argument parameter block.
 
 .Parameter Left
  The left (first) sequence or stream of Objects from the Powershell pipeline.
 
 .Parameter Right
  The right (second) sequence or stream of Objects from the Powershell pipeline.
 
 .Example
   # Multiple each element of a list by a factor from another list.
   Convert-PairMap -InputObject @(1,2,3) -Right @(4,5,6) { param($l,$r) $l * $r }
   4
   10
   18
 .Example
   # Multiple each element of a list by a factor from another list.
   @(1,2,3) | Convert-PairMap -Right @(4,5,6) { param($l,$r) $l * $r }
   4
   10
   18
 .Example
   # Zip two lists into a list of pairs.
   @(1,2,3) | Convert-PairMap -Right @(4,5,6) { param($l,$r) @($1,$r) } -OutVariable pairs
   $pairs.Count
   3
   $pairs[1]
   2
   5
#>

function Convert-PairMap
{
    [cmdletbinding()]
    param (
        [Parameter(Mandatory)]
        [ValidateScript({ $_.Ast.ParamBlock.Parameters.Count -eq 2 })]
        [Scriptblock] $Expression,

        [Parameter(Mandatory,ValueFromPipeline)]
        [object[]] $InputObject,

        [Parameter(Mandatory)]
        [object[]] $Right
    )

    begin { if ( $InputObject ) { $Left = $InputObject } }

    process { if ( $input ) { $Left = $Left + @( $_ ) } }

    end { [System.Linq.Enumerable]::Zip($Left, $Right, [Func[Object, Object, Object[]]]$Expression) }
}

<#
 .Synopsis
  Perform functional-style filter-to-select operations on a sequence or stream of objects in a Powershell pipeline
 
 .Description
  Apply the given ScriptBlock expression to each member of the pipelined InputObject, selecting those for which the expression is True.
 
 .Parameter Expression
  The anonymous (in-place) or named (as variable) single-argument lambda function to be applied to each InputObject element. This must have a single-argument parameter block.
 
 .Parameter InputObject
  The sequence or stream of Objects from the Powershell pipeline.
 
 .Example
   # Pick out the 2's from a stream
   @(1,2,3) | Search-Select { param($it) $it -eq 2 }
   2
 
 .Example
   # Pick out the 2's from a list
   Search-Select { param($it) $it -eq 2 } -InputObject @(1,2,3)
   2
#>
 
function Search-Select
{
    [cmdletbinding()]
    param (
        [Parameter(Mandatory)]
        [ValidateScript({ $_.Ast.ParamBlock.Parameters.Count -eq 1 })]
        [Scriptblock] $Expression,
 
        [Parameter(Mandatory = $true,
            ValueFromPipeline = $true)]
        [object[]] $InputObject
    )

    begin { if ( $InputObject ) { $InputObject | Where-Object { ( &$Expression $_ ) -eq $true } } }

    process { if ( &$Expression $_ ) { $_ } }
}

<#
 .Synopsis
  Perform functional-style filter-to-reject operations on a sequence or stream of objects in a Powershell pipeline
 
 .Description
  Apply the given ScriptBlock expression to each member of the pipelined InputObject, rejecting those for which the expression is True.
 
 .Parameter Expression
  The anonymous (in-place) or named (as variable) single-argument lambda function to be applied to each InputObject element. This must have a single-argument parameter block.
 
 .Parameter InputObject
  The sequence or stream of Objects from the Powershell pipeline.
 
 .Example
   # Reject the 2's from a stream
   @(1,2,3) | Search-Reject { param($it) $it -eq 2 }
   1
   3
 
 .Example
   # Reject out the 2's from a list
   Search-Reject { param($it) $it -eq 2 } -InputObject @(1,2,3)
   1
   3
#>
 
function Search-Reject
{
    [cmdletbinding()]
    param (
        [Parameter(Mandatory)]
        [ValidateScript({ $_.Ast.ParamBlock.Parameters.Count -eq 1 })]
        [Scriptblock] $Expression,
 
        [Parameter(Mandatory = $true,
            ValueFromPipeline = $true)]
        [object[]] $InputObject
    )

    begin { if ( $InputObject ) { $InputObject | Where-Object { ( &$Expression $_ ) -ne $true } } }

    process { if ( -Not ( &$Expression $_ ) ) { $_ } }
}