6

I have an array of objects:

$people= @()
foreach ($person in $databaseOfGuests)
{
   $people += @{ "FirstName"=$person.FirstName; "LastName"=$person.LastName } 
}

Now I want to remove duplicates from $people, is it possible to do this in PowerShell? Something like:

$people = $people | Select -Uniq

I have two arrays $people1 and $people2, I need to get array of all people that are in $people1 but not in the $people2 and vise versa. Something like:

$peopleInPeople1ButNotInPeople2 = $people1.Substruct($people2)
$peopleInPeople2ButNotInPeople1 = $people2.Substruct($people1)

Is it possible to do it in one line in PS?

2
  • You should go $people += $person instead. Then you can compare using -notin operator Commented Nov 20, 2017 at 10:10
  • As an aside: Extending arrays in a loop with += is inefficient, because a new array must be created behind the scenes in every iteration, given that arrays are of fixed size; a much more efficient approach is to use a foreach loop as an expression and let PowerShell itself collect the outputs in an array: [array] $outputs = foreach (...) { ... } - see this answer. In case you need to create arrays manually, e.g. to create multiple ones, use an efficiently extensible list type - see here. Commented Jan 1 at 22:43

4 Answers 4

11

Try this:

$people1 | ? {$_ -notin $people2}

or you can filter by property, like firstname or lastname:

$people1 | ? {$_.Firstname -notin $people2.Firstname}
  • the -notin operator is available on PS3 and above, for lower versions you can use -notcontains
Sign up to request clarification or add additional context in comments.

1 Comment

This is conceptually straightforward, but also inefficient, though with smallish input arrays you may not care. It is inefficient, because a linear search of array $people2 is performed for each and every element of array $people1.
2

My first thought was to fall back to the .NET Framework and use LINQ. But it turns out that the PowerShell syntax is pretty ugly:

[Linq.Enumerable]::Except([object[]] $people1, [object[]] $people2)

(I'm not sure why the object[] casts are necessary, but without them PowerShell throws an "Cannot find an overload for "Except" and the argument count: "2"" exception.)

1 Comment

Nice - much faster than the other solutions, though note that it is a pure set operation. Windows PowerShell (the only edition available at the time you posted your answer) lacks syntax for calling generic methods, so the casts are needed to allow it to infer the generic type argument. (though you could argue that it should default to [object[]]). PowerShell (Core) 7, in v7.3+ now has dedicated syntax, which allows simplifying the call to [Linq.Enumerable]::Except[object]($people1, $people2)
0

The idiomatic PowerShell would be:

$people1 | Where-Object { $people2 -notcontains $_ }

1 Comment

I tried this way and it didn't work for me, maybe because I add new objects to the array in a wrong way - += @{ "FirstName"=$person.FirstName; "LastName"=$person.LastName }
0

Additionally following code mimics different SET operations (Union, Subtraction & Minus) that can be used with PowerShell Arrays:

#assume variables $a and $b contain two sets of integer arrays:
$a = (1,2,3,4)
$b = (1,2,77,88)

'UNION: - merges both the outputs + removes the duplicate values'
Compare-Object $a $b -PassThru -IncludeEqual                    # union
#"Output: 1,2,77,88,3,4"

'INTERSECTION: - returns only common values'
Compare-Object $a $b -PassThru -IncludeEqual -ExcludeDifferent  # intersection
#"Output: 1,2"

'MINUS: - returns only exclusions'
'$a minus $b:'
$a | ?{$b -notcontains $_}                                      # a -minus b
#"Output: 3,4"

'$b minus $a:'
$b | ?{$a -notcontains $_}                                      # b -minus a
#"Output: 77,88"

1 Comment

+1 for mentioning Compare-Object, though note that it does not perform set operations (it only happens to do so if the input collections happen to be sets). Introducing true set operations is the subject of the (languishing) feature request in GitHub issue #4316. The "MINUS" operations you're showing are inefficient, and best avoided except for smallish arrays; a faster Compare-Object solution is possible.

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.