В Powershell, как я могу проверить, существуют ли все элементы из одного массива во втором массиве?

Итак, скажем, у меня есть этот массив:

$requiredFruit= @("apple","pear","nectarine","grape")

И мне присваивается второй массив под названием $fruitIHave. Как я могу проверить, что $fruitIHave имеет все в $requiredFruit. Не имеет значения, есть ли больше элементов в $fruitIHave, пока все в $requiredFruit есть.

Я знаю, что могу просто перебирать список, но это кажется неэффективным, есть ли встроенный метод для этого?

Ответ 1

Попробуйте 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

Ответ 2

Если у вас есть массивы:

$requiredFruit= @("apple","pear","nectarine","grape")
$someFruit= @("apple","banana","pear","nectarine","orange","grape")
$moreFruit= @("apple","banana","nectarine","grape")

Вы можете получить логический результат с помощью:

'Check $someFruit for $requiredFruit'
-not @($requiredFruit| where {$someFruit -notcontains $_}).Count

'Check $moreFruit for $requiredFruit'
-not @($requiredFruit| where {$moreFruit -notcontains $_}).Count

Использование подсчета массива защищает от единственного значения, которое не соответствует, которое оценивается как False. Например:

# Incorrect result
-not (0| where {(1,2) -notcontains $_})

# Correct result
-not @(0| where {(1,2) -notcontains $_}).Count

С помощью PowerShell v3 вы можете использовать select -first 1 для остановки конвейера при обнаружении первого несоответствия (в v2 select -first 1 разрешается только один объект, но предыдущие элементы конвейера продолжают обрабатываться).

-not @($requiredFruit| where {$moreFruit -notcontains $_}| select -first 1).Count

Ответ 3

Не совсем "встроенный", но:

[regex] $RF_regex = ‘(?i)^(‘ + (($requiredFruit |foreach {[regex]::escape($_)}) –join "|") + ‘)$’

($fruitIHave -match $RF_regex).count -eq $requiredFruit.count

Это создает переменное регулярное выражение из элементов $requiredFruit. Совпадает с $fruitIHave, он вернет все элементы, которые соответствуют. Если $fruitIhave может иметь дубликаты одних и тех же фруктов, вам может понадобиться запустить результат совпадения с помощью get-unique, прежде чем вы сделаете подсчет. Это может быть медленнее, чем повторение списка для одного сравнения, но как только вы создадите регулярное выражение, он будет выполнять повторяющиеся совпадения очень эффективно.

Ответ 4

Так или иначе, вам придется перебирать один или оба массива. Здесь используется однострочный подход:

$hasAllRequiredFruit = ($requiredFruit | Where-Object { $fruitIHave -contains $_ }).Length -eq $requiredFruit.Length;
Цикл

A foreach был бы лучше, потому что вы можете остановить итерацию, как только найдете нужный плод:

$hasAllRequiredFruit = $true;
foreach ($f in $requiredFruit)
{
    if ($fruitIHave -notcontains $f)
    {
       $hasAllRequiredFruit = $false;

       break;
    }
}