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

Допустим, у меня есть этот массив:

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

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

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

Ответы [ 4 ]

25 голосов
/ 22 марта 2012

Вы пытаетесь сравнить объект:

$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
14 голосов
/ 22 марта 2012

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

$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
1 голос
/ 22 марта 2012

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

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

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

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

       break;
    }
}
1 голос
/ 22 марта 2012

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

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...