# Tahir Hassan's Blog

My Technical Notes

## Thursday, 3 March 2016

### SkipUntil and TakeUntil in PowerShell

Given a list [ x1, x2, x3, ..., xn] and a predicate p, SkipUntil will skip over the elements until it finds an xi such that p(xi) holds. At this point it returns xi together with the rest of the list, therefore returning [xi, x(i + 1), ..., xn]. We can optionally exclude xi.

Given a list [ x1, x2, x3, ..., xn] and a predicate p, TakeUntil will yield each element until it finds an xi such that p(xi) holds. At this point it returns xi and stops iterating over the list, therefore returning [ x1, ..., xi]. We can optionally exclude xi.

Here is the PowerShell module:


Function SkipUntil-Object
{
param(
[Parameter(Mandatory=$true, Position=0)][ScriptBlock]$Predicate,
[Parameter(Mandatory=$true, ValueFromPipeline=$true)]$ObjectSet, [Parameter()][alias("x")][switch]$ExcludeMatch
)

begin {
$foundMatch =$false;
}

process {
foreach ($o in$ObjectSet) {
if ($foundMatch) {$o;
} else {
if ($o | %$Predicate) {
$foundMatch =$true;
if (-not $ExcludeMatch) {$o;
}
}
}

}
}
}

Set-Alias skipuntil SkipUntil-Object

Function TakeUntil-Object
{
param(
[Parameter(Mandatory=$true, Position=0)][ScriptBlock]$Predicate,
[Parameter(Mandatory=$true, ValueFromPipeline=$true)]$ObjectSet, [Parameter()][alias("x")][switch]$ExcludeMatch,
[Parameter()][switch]$StopPipeline ) begin {$foundMatch = $false; } process { if (-not$foundMatch) {
foreach ($o in$ObjectSet) {
if ($o | %$Predicate) {
if (-not $ExcludeMatch) {$o;
}

if ($StopPipeline) { throw [System.Management.Automation.PipelineStoppedException]::new() } else {$foundMatch = $true; } } else {$o;
}
}
}
}
}

Set-Alias takeuntil TakeUntil-Object

Export-ModuleMember -Function * -Alias *


#### Code samples


1..100 | takeuntil { $_ -eq 50 } # => 1..50 'matthew', 'mark', 'luke', 'john' | skipuntil {$_ -match '^l.*' }
# => 'luke', 'john'
'matthew', 'mark', 'luke', 'john' | skipuntil { $_ -match '^l.*' } -x # => 'john' because we have used the -ExcludeMatch switch  #### References •$linq: Javascript LINQ library This was the only page online I could find which included, by default the matched element xi in the result set.
• ReactiveX: SkipUntil - although they are discarding the item at which the match occurs and I am including it (by default), it still serves as a nice illustration of the concept.
• powershell.com: Cancelling a Pipeline - tells us how to cancel a pipeline, used in the TakeUntil-Object implementation.
• jaredpar: PowerShell LINQ Take-Count and Take-While - this provided some inspiration for my implementation.
• GitHub: MoreLINQ - This extension library contains an implementation of TakeUntil, which takes upto and including the matched element with no option for match exclusion, and an implementation of SkipUntil which skips all elements upto and including the matched element, i.e. it excludes the match, with no option of inclusion.