The .NET method Linq.Enumerable.Join seems to be pretty fast. As it's not immediately obvious how to use it from PowerShell (you need some casts to be able to pass ScriptBlock
s to its selector parameters), I've wrapped it in a PowerShell function Join-Enumerable
to make it easier to use.
Function Join-Enumerable{
[CmdletBinding()]
param (
[Parameter(Mandatory)]
[Collections.IEnumerable] $Left,
[Parameter(Mandatory)]
[Collections.IEnumerable] $Right,
[Parameter(Mandatory)]
$LeftKey,
[Parameter(Mandatory)]
$RightKey,
[Parameter(Mandatory)]
[scriptblock] $Result,
[Parameter()]
[switch] $NoEnumerate
)
if( $RightKey -isnot [scriptblock] ) {
$RightKey = "$RightKey" -replace "'", "''"
$RightKey = [scriptblock]::Create( "`$args[0].'$RightKey'" )
}
if( $LeftKey -isnot [scriptblock] ) {
$LeftKey = "$LeftKey" -replace "'", "''"
$LeftKey = [scriptblock]::Create( "`$args[0].'$LeftKey'" )
}
$enumerator = [Linq.Enumerable]::Join( $Left, $Right,
[Func[object, object]] $RightKey,
[Func[object, object]] $LeftKey,
[Func[object, object, object]] $Result )
if( $NoEnumerate ) {
return , $enumerator # Outputs the enumerator itself
}
$enumerator # Enumerates and outputs each result element
}
Demo:
$df1 = ConvertFrom-Csv @'
Name,Foo
foo,1
bar,2
baz,3
'@
$df2 = ConvertFrom-Csv @'
Name,Bar
bar,4
bam,5
foo,6
'@
$joinedArray = Join-Enumerable -Left $df1 -Right $df2 -LeftKey Name -RightKey Name -Result {
[PSCustomObject] @{
Name = $args[0].Name
Foo = $args[0].Foo
Bar = $args[1].Bar
}
}
$joinedArray # Output
Output:
Name Foo Bar
---- --- ---
foo 1 6
bar 2 4
Remarks:
Performance tests:
For comparing performance I used the this code. Each test script creates two arrays of 100000 elements each, with random name
properties. The name
properties of the 2nd array match elements from the 1st array randomly. 10 runs are done for each method and the average duration is taken.
Method |
Input |
Output |
Duration |
Join-Enumerable |
class object |
class object |
1.4 s |
Join-Enumerable |
class object |
[PSCustomObject] |
2.62 s |
Join-Enumerable |
[PSCustomObject] |
[PSCustomObject] |
4.6 s |
Join-Object (iRon) |
class object |
[PSCustomObject] |
36.2 s |
Join-Object (RamblingCookieMonster) |
class object |
[PSCustomObject] |
44.4 s |