Finding common elements in two PowerShell arrays

I know there are a few questions on this already, but I've tried many solutions and keep getting the same error. The problem is this:

I have 2 arrays (each index represents a folder)

$originDirsArr = @(2, 257, 256, 3, 4, 10)
$tempDirArr = @(2, 257, 256, 3, 4)

      

I want to compare $ arr2 again with $ arr1 and if there is something in $ arr1 not in $ arr2, then Delete. Those. in this situation 10 DNEs in $ arr2, so the folder must be deleted.

Here's what I've tried:

$c = Compare-Object -ReferenceObject ($originDirsArr) `
 -DifferenceObject ($tempDirArr) -Passthru
$c

      

Also:

while ($t -lt $originDirsArr.length){
$originDirsArr[$t]
    if ( $tempDirArr -notContain $originDirsArr[$t]){
        "$_ does not exist in original and needs to be deleted"
    }else{
        "$_ does still exist in the temp"
    }
    $t++
}

      

Finally:

Compare-Object $originDirsArr $tempDirArr | ForEach-Object { $_.InputObject }

      

Every time I get some error, either is ReferenceObject or DifferenceObject is null. I know it is not null because I can print the content and even index by t in this example, I still have the content.

Thanks in advanced, any help would be greatly appreciated!

+3


source to share


3 answers


I also have an aversion to compare-object

. Since these are simple arrays, one trick foreach

and -notcontains

will do the trick.



$originDirsArr = @(2, 257, 256, 3, 4, 10)
$tempDirArr = @(2, 257, 256, 3, 4)

foreach ($item in $originDirsArr) {
    if ($tempDirArr -notcontains $item) {
        Write-Output "Do something with $item";
    }
}

      

+4


source


Use a shared collection HashSet . It requires .NET 3.5. It has an IntersectWith method that will modify a set that only includes items in both collections (for example, AND

with two collections):

$originDirsSet = New-Object 'Collections.Generic.HashSet[int]' ,@(2, 257, 256, 3, 4, 10)
$tempDirSet = @(2, 257, 256, 3, 4)
$originDirsSet.IntersectWith( $tempDirSet )
# $originalDirsSet now contains 2, 257, 256, 3, 4

      



It has other set based methods:

  • ExceptWith

    : removes all elements in the specified collection from the current object HashSet<T>

    .
  • SymmetricExceptWith

    : Modifies the current object HashSet<T>

    , containing only those elements that are present either in this object or in the specified collection, but not both (i.e. it looks like a XOR

    collection).
  • UnionWith

    : Modifies the current object HashSet<T>

    , containing all the items present in it, the specified collection, or both (that is, it looks like a OR

    collection).
+2


source


Here is 1 liner for that. This is the same as the accepted answer in that it iterates through one array then uses it -contains

to compare that element with another array. The difference here is that we are using a function where-object

and returning a result set instead of having an if statement in a for loop. Also, the use of PowerShell shorthand to reduce the amount of code (good or bad smart is controversial).

#setting up
$originDirsArr = @(2, 257, 256, 3, 4, 10)
$tempDirArr = @(2, 257, 256, 229, 3, 4)

#get items in 1 array but not the other 
[int[]]$leftOnly = $originDirsArr | ?{$tempDirArr -notcontains $_}

#or an intersect operation
[int[]]$intersect = $originDirsArr | ?{$tempDirArr -contains $_}

#display results
"Left Only"; $leftOnly 
"Intersect"; $intersect 

      

Or, if you do this a lot, it might be helpful to have a handy function for this type of operation:

set-alias ?@@ Apply-ArrayOperation #http://stackoverflow.com/a/29758367/361842
function Apply-ArrayOperation {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory, Position=0)]
        [object[]]$Left
        ,
        [Parameter(Mandatory,ParameterSetName='exclude', Position=1)]
        [switch]$exclude
        ,
        [Parameter(Mandatory,ParameterSetName='intersect', Position=1)]
        [switch]$intersect
        ,
        [Parameter(Mandatory,ParameterSetName='outersect', Position=1)] #not sure what the correct term for this is
        [switch]$outersect
        ,
        [Parameter(Mandatory,ParameterSetName='union', Position=1)] #not sure what the correct term for this is
        [switch]$union
        ,
        [Parameter(Mandatory,ParameterSetName='unionAll', Position=1)] #not sure what the correct term for this is
        [switch]$unionAll
        ,
        [Parameter(Mandatory, Position=2)]
        [object[]]$Right
    )
    begin {
        #doing this way so we can use a switch staement below, whilst having [switch] syntax for the function caller 
        [int]$action = 1*$exclude.IsPresent + 2*$intersect.IsPresent + 3*$outersect.IsPresent + 4*$union.IsPresent + 5*$unionAll.IsPresent
    }
    process {
        switch($action) {
            1 {$Left | ?{$Right -notcontains $_}} 
            2 {$Left | ?{$Right -contains $_} }
            3 {@($Left | ?{$Right -notcontains $_}) + @($Right | ?{$Left -notcontains $_})}       
            4 {@($Left) + @($Right) | select -Unique}       
            5 {@($Left) + @($Right)}       
        }
    }
}

$array1 = @(1,3,5,7,9)
$array2 = @(2,3,4,5,6,7)

"Array 1"; $array1
"Array 1"; $array2

"Array 1 Exclude Array 2";   ?@@ $array1 -exclude $array2 
"Array 1 Intersect Array 2"; ?@@ $array1 -intersect $array2
"Array 1 Outersect Array 2"; ?@@ $array1 -outersect $array2
"Array 1 Union Array 2";     ?@@ $array1 -union $array2
"Array 1 UnionAll Array 2";  ?@@ $array1 -unionall $array2

      

+1


source







All Articles