альтернативы сценария foreach для более быстрого выполнения - PullRequest
1 голос
/ 12 марта 2020

У меня есть приведенный ниже код, который делает то, что мне нужно, но он медленный, мне интересно, есть ли более быстрые альтернативы, которые могли бы сделать то же самое.

$array2= ('italy', 'mexico', 'australia')

$pattern = '(?:total residents\s: )\W(\d+)\W'

$array = $array2 | ForEach-Object {
    $array3 = Get-ChildItem -Path $path -Recurse | Select-string -Pattern $_ -SimpleMatch -Context 9, 0 | ForEach-Object { 
        $_.Context.PreContext
        $_.Line
        $_.Context.PostContext
    }
    $array3 | Select-String -Pattern $pattern | ForEach-Object { $_.Matches.Groups[1].Value }
}

$ array2 может иметь элементы до 10, это только пример с 3.

файл содержит данные в следующем формате. Точки представляют другую информацию, мне не нужно, это только то, как ее часть выглядит так, что линия страны на 9 строк ниже общего количества жителей.

всего жителей: (15899630)
.
.
.
.
.
.
.
.
страна: Италия

================================================= ===========

Вывод вышеуказанного скрипта:

15899630
2442110
1500000

Ответы [ 3 ]

3 голосов
/ 12 марта 2020

Может быть полезно знать шаблон регулярного выражения и формат ввода ваших данных, но на основе предоставленного примера сценария я бы предложил:

  • Только чтение каждого файла только один раз
  • Замена вашего второго Select-String вызова на -match/$matches

Что-то вроде:

foreach($file in Get-ChildItem -Path $path -Recurse -File){
    foreach($item in $array2){
        $file |Select-String -Pattern $item -SimpleMatch -Context 9, 0 |ForEach-Object { 
            $_.Context.PreContext
            $_.Line
        } |ForEach-Object {
            if($_ -match $pattern){
                $Matches[1]
            }
        }
    }
}
1 голос
/ 12 марта 2020

Недостаточно деталей в вашем вопросе, чтобы создать правильный ответ (и проверить его), но кэширование соответствует моей справке в зависимости от содержимого ваших файлов, массивов и $Pattern:

Как правило, вы можете подойти к этому (, но не можете проверить ):

$Cache = @{}
Function GetMatch($Item) {
    If (!$Cache.ContainsKey($Item)) {
        $Text = Get-ChildItem -Path $path -Recurse | Select-string -Pattern $Item -SimpleMatch -Context 9, 0 | ForEach-Object { 
            $_.Context.PreContext
            $_.Line
            $_.Context.PostContext
        }
        $Cache[$Item] = $Text | Select-String -Pattern $pattern | ForEach-Object { $Item.Matches.Groups[1].Value }
    }
    $Cache[$Item]
}

$array = $array2 | ForEach-Object {
    $array3 = GetMatch $_
}

(обратите внимание, что я основал это исключительно на вашем примере в вашем вопросе и даже не пытался приспособить действительные ответы от других, которые я рекомендую вам попробовать объединить.)

1 голос
/ 12 марта 2020

Поскольку Select-String принимает массив шаблонов, я не вижу причин для передачи такого массива таким образом.

Возможно, это не работает, но я думаю, что он движется в правильном направлении:

Примечание: объединение некоторых работ Матиаса Р. Джессена, приведенных ниже:

$Result =
Get-ChildItem $Path -Recurse -File |
Select-String -Pattern $Array2 -SimpleMatch -Context 9, 0 |
ForEach-Object{
    $_.Context.PreContext
    $_.Line
    } |
ForEach-Object{
    If( $_ -match $pattern ) { $_.Matches[1] }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...