Reputation: 34223
So let's say I have this array:
$requiredFruit= @("apple","pear","nectarine","grape")
And I'm given a second array called $fruitIHave
. How can I check that $fruitIHave
has everything in $requiredFruit
. It doesn't matter if there are more items in $fruitIHave
just as long as everything in $requiredFruit
is there.
I know I could just iterate over the list, but that seems inefficient, is there a built-in method for doing this?
Upvotes: 18
Views: 42657
Reputation: 24343
If you have the arrays:
$requiredFruit= @("apple","pear","nectarine","grape")
$someFruit= @("apple","banana","pear","nectarine","orange","grape")
$moreFruit= @("apple","banana","nectarine","grape")
You can get a boolean result with:
'Check $someFruit for $requiredFruit'
-not @($requiredFruit| where {$someFruit -notcontains $_}).Count
'Check $moreFruit for $requiredFruit'
-not @($requiredFruit| where {$moreFruit -notcontains $_}).Count
Using the count of an array protects against a single value not matching that evaluates as False. For example:
# Incorrect result
-not (0| where {(1,2) -notcontains $_})
# Correct result
-not @(0| where {(1,2) -notcontains $_}).Count
With PowerShell v3, you can use select -first 1
to stop the pipeline when the first mismatch is found (in v2 select -first 1
allows only one object through, but previous elements of the pipeline continue to process).
-not @($requiredFruit| where {$moreFruit -notcontains $_}| select -first 1).Count
Upvotes: 17
Reputation: 72680
Do you try Compare-Object :
$requiredFruit= @("apple","pear","nectarine","grape")
$HaveFruit= @("apple","pin","nectarine","grape")
Compare-Object $requiredFruit $haveFruit
InputObject SideIndicator
----------- -------------
pin =>
pear <=
Compare-Object $requiredFruit $haveFruit | where {$_.sideindicator -eq "<="} | % {$_.inputobject}
pear
Upvotes: 28
Reputation: 16612
One way or the other, you're going to have to iterate through one or both arrays. Here's a one-liner approach:
$hasAllRequiredFruit = ($requiredFruit | Where-Object { $fruitIHave -contains $_ }).Length -eq $requiredFruit.Length;
A foreach
loop would be better because you can stop iterating as soon as you find a required fruit that is missing:
$hasAllRequiredFruit = $true;
foreach ($f in $requiredFruit)
{
if ($fruitIHave -notcontains $f)
{
$hasAllRequiredFruit = $false;
break;
}
}
Upvotes: 1
Reputation: 68341
Not exactly "builtin" but:
[regex] $RF_regex = ‘(?i)^(‘ + (($requiredFruit |foreach {[regex]::escape($_)}) –join “|”) + ‘)$’
($fruitIHave -match $RF_regex).count -eq $requiredFruit.count
That creates an alternating regex from the elements of $requiredFruit. Matched against $fruitIHave, it will return all the items that matched. If $fruitIhave could potentially have duplicates of the same fruit you may need to run that match result through get-unique before you do the count. It may be slower than iterating over the list for a single comparison, but once you have the regex built it will do repetitive matches very efficiently.
Upvotes: 1