I suggest using the Compare-Object
cmdlet in combination with the .Where()
array method:
$arr1 = 1,1,1,2,2,3,4,4,5,7
$arr2 = 1,2,3,4,5,6,7
$inBoth, $uniqueRight =
(Compare-Object -PassThru -IncludeEqual `
($arr1 | Select-Object -Unique) ($arr2 | Select-Object -Unique)).
Where({ $_.SideIndicator -in '==', '=>' }).
Where({ $_.SideIndicator -eq '==' }, 'Split')
"-- in both:"
$inBoth
"-- unique to arr2"
$uniqueRight
Note: Thanks to using Select-Object -Unique
on the input arrays so as to only operate on distinct elements, the use of -PassThru
with Compare-Object
works as expected and passes the integers of interest through directly, rather than as properties of wrapper objects. The caveat is that with [int]
array elements specifically, because PowerShell caches values up to 100
, having duplicates in either collection would malfunction obscurely. The reason is that -PassThru
decorates the pass-through elements with an ETS .SideIndicator
property, which affects all uses of a given integer between 0
and 100
, so that the .SideIndicator
property value of a later duplicate would overwrite the original value - see this answer for more information.
Note:
If you know that the distinct elements of $arr1
are only ever a subset of the ones in $arr2
, i.e. that $arr1
contains no unique elements, you can eliminate the intermediate .Where({ $_.SideIndicator -in '==', '=>' })
call.
Unfortunately, as of PowerShell 7.2, the implementation of Select-Object
-Unique
is quite inefficient - see GitHub issue #11221. If the input arrays were sorted, Get-Unique
would be a faster alternative.
The above yields:
-- in both (distinct):
1
2
3
4
5
7
-- unique to arr2
6