7

I have two arrays in Powershell. Each Array contains an array of objects. These objects have two properties:

Name: String
Id: GUID

The first Array has 4413 objects in it and the second has 4405. The counts are irrelevant, but I only mention them to note that the contents of Array1 and Array2 are different.

Here is my current code (pseudo):

#Fill Array1
$Array1 = Fill-Array1

#Fill Array2
$Array2 = Fill-Array2

#Loop through the arrays and write out the names of all items in Array2 that are different than Array1
ForEach($Val in $Array2)
{
    $Name = $Val.Name

    If($Array1 -notcontains $Val) //this does not work
    {
        Write-Host $Name
    }
}

What is the correct way to check for the existence of the object in Array1? Is my only option to do a nested loop?

Update, using the answer from Manu P below, the following is how I implemented the solution:

#Fill Array1
    $Array1 = Fill-Array1
    
    #Fill Array2
    $Array2 = Fill-Array2
    
    #Compare the arrays
    $ComparedResults = Compare-Object -ReferenceObject $Array1 -DifferenceObject $Array2 #I left out the -IncludeEqual param because I don't care about those results

    ForEach($Result in $ComparedResults)
    {
        If($Result.SideIndicator -eq "=>") #the value in Array2 is different than Array1
        {
            $Val = $Result.InputObject

            Write-Host $Val.Name            
        }        
    }
2
  • 1
    When I do this exact same method using 2 arrays with just some random numbers in them, it works perfectly. Maybe it has something to do with the type of object in the arrays? Commented Aug 9, 2017 at 16:59
  • 2
    @CoryEtmund google "reference equality vs value equality" :-) Commented Aug 9, 2017 at 17:07

4 Answers 4

11

You can use Compare-Object cmdlet :

Compare-Object -ReferenceObject $Array1 -DifferenceObject $Array2 -IncludeEqual

https://learn.microsoft.com/fr-fr/powershell/module/Microsoft.PowerShell.Utility/Compare-Object?view=powershell-5.0

https://technet.microsoft.com/fr-fr/library/ee156812.aspx

Sign up to request clarification or add additional context in comments.

1 Comment

I implemented this solution in my Question with notes
3

Continuing off from what Manu gave, this helped me a lot, I was interesting in something similar but matching on one property within an object, what I used was like this. This example adds unmatched to the end of an object. The last line of code strips off the SideIndicator that gets added in the process.

$remainder = Compare-Object -ReferenceObject $a -DifferenceObject $b -Property "mail" -PassThru | where-object SideIndicator -eq "<="
$b += $remainder
$b = $b | Select-Object -Property * -ExcludeProperty SideIndicator

Comments

2

As GUIDs are comparable you can simply (inner)join the arrays using the function described here: https://stackoverflow.com/a/45483110/1701026

$Array1 = @(
    [pscustomobject]@{Name = "a"; Id = [guid]::NewGuid()}
    [pscustomobject]@{Name = "b"; Id = [guid]::NewGuid()}
    [pscustomobject]@{Name = "c"; Id = [guid]"de5e32c6-5338-4287-8c21-2dd5957cfffe"}
    [pscustomobject]@{Name = "d"; Id = [guid]"345f9ac2-86a0-4b01-b843-5f4bd55f5e21"}
    [pscustomobject]@{Name = "e"; Id = [guid]"953c1442-ed51-445e-a8f5-687120d98f83"}
    [pscustomobject]@{Name = "f"; Id = [guid]::NewGuid()}
)

$Array2 = @(
    [pscustomobject]@{Name = "b"; Id = [guid]::NewGuid()}
    [pscustomobject]@{Name = "c"; Id = [guid]"345f9ac2-86a0-4b01-b843-5f4bd55f5e21"}
    [pscustomobject]@{Name = "d"; Id = [guid]"345f9ac2-86a0-4b01-b843-5f4bd55f5e21"}
    [pscustomobject]@{Name = "e"; Id = [guid]"953c1442-ed51-445e-a8f5-687120d98f83"}
    [pscustomobject]@{Name = "f"; Id = [guid]"953c1442-ed51-445e-a8f5-687120d98f83"}
    [pscustomobject]@{Name = "g"; Id = [guid]::NewGuid()}
)

$Array1 | InnerJoin $Array2 -Using Name,Id | Format-Table

Result:

Id                                   Name
--                                   ----
345f9ac2-86a0-4b01-b843-5f4bd55f5e21 d
953c1442-ed51-445e-a8f5-687120d98f83 e

To get all records with the same name where Id is not equal:

$Array1 | InnerJoin $Array2 -on {$Left.Name -eq $Right.Name -and $Left.Id -ne $Right.Id} -Merge @{Name = {$Left.$_}} | Format-Table

Result:

Id                                                                           Name
--                                                                           ----
{3b175777-e88f-4248-965b-51dec8639fd6, a43d68de-9ed5-4a13-8f8e-61c6cc501458} b
{de5e32c6-5338-4287-8c21-2dd5957cfffe, 345f9ac2-86a0-4b01-b843-5f4bd55f5e21} c
{2a8c4bf7-cf3a-4c3d-b27b-ecb6f4a4fa43, 953c1442-ed51-445e-a8f5-687120d98f83} f

1 Comment

This is a really nice idea, but it gives me the equal values when I want what is different.
1

as extention to user Manu answer

$arr1=@(1,2,3,'word')
$arr2=@('4','5','3')
((Compare-Object -ReferenceObject $arr1 -DifferenceObject $arr2 -IncludeEqual).SideIndicator -contains '==')

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.