Как я могу включить массивы, чтобы сравнить одно значение со всеми значениями в массиве? - PullRequest
1 голос
/ 05 октября 2019

Я новичок в написании сценариев и борюсь с реализацией некоторых концепций. У меня работает скрипт PowerShell, который будет принимать ввод от пользователя и сохранять его в нескольких переменных. Затем он просматривает файл .csv и выводит только те строки, в которых несколько входных данных пользователя не совпадают со значением в указанном столбце.

Например, если у меня есть файл .csv, содержащий:

value1, value2, value3
data1, data2, data3
data1, data2, data3
data1, data5, data3
data1, data2, data3

И я прошу вывести строки, в которых значение2 отличается от data5, в качестве вывода я получаю следующее:

value1, value2, value3
data1, data2, data3
data1, data2, data3
data1, data2, data3

Вот мой текущий код, который работает:

$path = Read-Host 'What is the file share path?'

$filteredvalue = Read-Host 'What value would you like to filter out?'
$filteredvalue2 = Read-Host 'What second value would you like to filter out?'
$filteredvalue3 = Read-Host 'What second value would you like to filter out?'
$filteredvalue4 = Read-Host 'What second value would you like to filter out?'
$filteredvalue5 = Read-Host 'What second value would you like to filter out?'
$filteredvalue6 = Read-Host 'What second value would you like to filter out?'
$filteredvalue7 = Read-Host 'What second value would you like to filter out?'


$file1 = $path

$filtered = Import-Csv -Path $file1 | where {$_.IdentityReference -notlike $filteredvalue -and $_.IdentityReference -notlike $filteredvalue2 -and $_.IdentityReference -notlike $filteredvalue3 -and $_.IdentityReference -notlike $filteredvalue4 -and $_.IdentityReference -notlike $filteredvalue5 -and $_.IdentityReference -notlike $filteredvalue6 -and $_.IdentityReference -notlike $filteredvalue7}

$file2 = "${path}_filtered.csv"

$filtered | Export-Csv -Path $file2 -NoTypeInformation

Это работает, но это не лучшее решение, так как я должен указать в коде, сколько значений я буду отфильтровывать. Я хотел бы использовать массивы, чтобы не создавать все переменные для значений.

Вот что я пробовал до сих пор, но не повезло:

$path = Read-Host 'What is the file share path?'

$Reponse = 'Y'
$filteredvalue = $Null
$filteredvalues = @()

Do 
{ 
    $filteredvalue = Read-Host 'What value would you like to filter out?'
    $Response = Read-Host 'Would you like to filter out additional values? (y/n)'
    $filteredvalues += $filteredvalue
}
Until ($Response -eq 'n')


$file1 = $path

$filtered = Import-Csv -Path $file1 | where {for($i = 0; $i -le $filteredvalues.GetUpperBound(0); $i++) {$_.IdentityReference -ne $filteredvalues[$i]}}


$file2 = "${path}_filtered.csv"

$filtered | Export-Csv -Path $file2 -NoTypeInformation

Вывод остается прежними ничего не отфильтровывается.

1 Ответ

0 голосов
/ 05 октября 2019

PowerShell предлагает операторы сравнения массивов -contains и, начиная с v3, также -in - они отличаются только тем, идет ли входной массив на LHS (-contains) или RHS (-in).

Как и большинство операторов в PowerShell, они также существуют в форме с отрицанием , то есть -notcontains и -notin.

. Применяются к вашему коду:

$filtered = Import-Csv $file1 | Where-Object IdentityReference -notin $filteredValues

Что касается того, что вы пытались :

В качестве отступления: проще использовать $filteredvalues.Count - 1 вместо $filteredvalues.GetUpperBound(0).

where (Where-Object) выбирает (пропускает) входные объекты в зависимости от того, оценивается ли вывод из блока сценария { ... } как $true.

Ваш код for возвращает цикл массив логических значений, указывающий для каждого значения фильтра , соответствует ли .IdentityReference входного объекта этому значению.

Следовательно, с двумя или более значениями фильтра вы будетезаканчивается массивом, который содержит по крайней мере 1 $true значение, и любой такой массив неизменно интерпретируется как $true в целом.

Например:

PS> [bool] ($false, $true)
True 

Обзор того, как PowerShell неявно оценивает объект как логическое (преобразование в логическое), см. В нижней части этого ответа .

Чтобы ваш циклический подход сработал, вам бы пришлось возвращать $false в качестве скаляра, как только значение фильтра соответствовало, и по умолчанию $true в противном случае (обратите внимание на использование foreach для перечисления элементов массиваудобнее):

$filtered = Import-Csv -Path $file1 | where {
  foreach ($filteredValue in $filteredValues) {
    if ($_.IdentityReference -eq $filteredValue) { return $false }
  }
  return $true
}

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