2017-01-26 2 views
1

Я пытаюсь обработать файл CSV размером 15 МБ, который имеет только три столбца. Например:Создание новых столбцов в CSV на основе рекурсивного поиска

StaffNumber,EmailAddress,Manager 
123,[email protected],456. 

мне нужно искать каждую строку файла CSV, отображает количество кадров, адрес электронной почты, а затем взять идентификационный номер менеджера и искать то, что, показывая их количество персонала и электронную почту, а затем возьмите их идентификатор менеджера и повторите то же самое. В конце концов, мне нужно, чтобы каждая строка CSV-файла имела идентификатор пользователя и адрес электронной почты, а - до трех идентификаторов менеджеров и электронной почты.

Я пытаюсь закончить с этим:

123,[email protected],456,[email protected],789,[email protected],098,[email protected] 

Некоторые строки не содержат адрес электронной почты или номер удостоверения личности менеджера, так что бросает еще один ключ в работах. Я планировал добавить в эти поля просто «Бланк» или «Х».

До сих пор я забил этот простой скрипт для поиска по одному. Это работает, но это ужасно медленно. С сегодняшнего утра прошло 6 часов, чтобы получить 0,31% через этот файл. Тьфу!

Я прочитал, пока не полностью смутил себя тем, как лучше всего обрабатывать данные CSV на 15 МБ, разные версии PowerShell, лучшие на этой неделе и т. Д., А PowerShell далек от моего обычного языка (пожалейте на мой недостаток PS. Я просто пытался создать базовый тестовый сценарий, чтобы получить представление).

В настоящее время я запускаю PowerShell v4, и я знаю, что есть проблемы совместимости с более ранними версиями. Я хотел бы попытаться оставаться совместимым с будущими версиями как разумное.

Что было бы самым быстрым способом обработки этого файла? Только за 15 МБ за 300 000 строк я не беспокоюсь о ОЗУ. Я просто не знаю, как более эффективно выполнять этот поиск.

$FilePath = "C:\Temp\DA-UserList.csv" 
$DAUserlist = Import-CSV $FilePath 

$inputNumber = Read-Host -Prompt "Employee ID Number" 

$DAUser1 = $DAUserlist | Where{$inputNumber -match $_.StaffNumber}| Select -First 1 
ForEach ($item in $DAUser1){ 
    $StaffNumber1 = $($item.StaffNumber) 
    $EmailAddress1 = $($item.EmailAddress) 
    $Manager1 = $($item.Manager) 
    printf $item.StaffNumber 
    printf "," 
    printf $EmailAddress1 
    $DAUser2 = $DAUserlist | Where{$Manager1 -match $_.StaffNumber}| Select -First 1 
    ForEach ($item in $DAUser2){ 
     $StaffNumber2 = $($item.StaffNumber) 
     $EmailAddress2 = $($item.EmailAddress) 
     $Manager2 = $($item.Manager) 
     printf "," 
     printf $StaffNumber2 
     printf "," 
     printf $EmailAddress2 
     $DAUser3 = $DAUserlist | Where{$Manager2 -match $_.StaffNumber}| Select -First 1 
     ForEach ($item in $DAUser3){ 
      $StaffNumber3 = $($item.StaffNumber) 
      $EmailAddress3 = $($item.EmailAddress) 
      $Manager3 = $($item.Manager) 
      printf "," 
      printf $StaffNumber3 
      printf "," 
      printf $EmailAddress3 
      $DAUser4 = $DAUserlist | Where{$Manager3 -match $_.StaffNumber}| Select -First 1 
      ForEach ($item in $DAUser4){ 
       $StaffNumber4 = $($item.StaffNumber) 
       $EmailAddress4 = $($item.EmailAddress) 
       $Manager4 = $($item.Manager) 
       printf "," 
       printf $StaffNumber4 
       printf "," 
       printf $EmailAddress4 
       printf \n 
      } 
     } 
    } 
} 

ответ

1

Ну, я думаю, что для 15MB файла, вам не нужен какой-либо хардкор оптимизаций (по крайней мере я так думаю). Итак, вы хотите использовать рекурсивную функцию, поскольку вы делаете одно и то же снова и снова.

$data = Import-Csv "C:\Temp\DA-UserList.csv" 
$i = 0 

function Get-CsvUser { 
    param(
     [string]$id 
    ) 

    $data.Where({$_.StaffNumber -eq $id}, 'First', 1) 
} 

function Get-CsvNested { 
    param(
     [string]$id 
    ) 

    $user = Get-CsvUser $id 
    Get-CsvUser -id $user.Manager | % { 
     while ($global:i -lt 3) { # using global here to avoid circular execution 
      $global:i++ 

      Write-Output "User: $($user.EmailAddress)" 
      Write-Output "His Manager: $($_.EmailAddress)" 

      "" # to output an empty string 
      Get-CsvNested -id $_.StaffNumber 
     } 
    } 
} 

, что, по крайней мере, выглядеть лучше и легче понять, как для исполнения, попробуйте использовать .where()method. Это быстрее.
Кроме того, вы можете разбить CSV на куски и создать отдельный процесс для разбора из кусков (думаю Start-Job или лучше Start-RSJob)

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

Если вам нужна дополнительная помощь, пинг меня здесь (или где-нибудь, проверьте мой профиль), мы можем что-то решить.

1

Каждый раз, когда вы выполняете что-то вроде $DAUserlist | Where { # ... } | Select -First 1, вы выполняете линейный поиск, как вы говорите, 300 000 записей. Вы можете ускорить это, используя Group-Object cmdlet, как ...

$DAUserlist = Import-CSV $FilePath 
$DAUsersByStaffNumber = $DAUserlist | Group-Object -Property 'StaffNumber' -AsHashTable 

$DAUsersByStaffNumber содержит HashTable экземпляр отображения каждого числа сотрудников к записи пользователя. Ваш код для поиска определенного пользователя и три их менеджеры могут затем быть заменен на следующем ...

$DAUser1 = $DAUsersByStaffNumber[$inputNumber] 
# ... 
$DAUser2 = $DAUsersByStaffNumber[$Manager1] 
# ... 
$DAUser3 = $DAUsersByStaffNumber[$Manager2] 
# ... 
$DAUser4 = $DAUsersByStaffNumber[$Manager3] 

Это упрощает код немного и делает ваши поиски намного более эффективными.

Кроме того, что-то, о чем следует помнить, заключается в том, что при фильтрации вашего списка пользователей по номеру персонала вы используете оператор -match, который поддерживает регулярные выражения, тогда как оператор -eq будет искать точное соответствие строк (case- нечувствителен). Одной из причин этого может быть проблема в том, что использование -match, когда вы не собираетесь выполнять сложное строковое сопоставление, поддерживаемое регулярными выражениями, может привести к снижению производительности по сравнению с -eq, хотя, возможно, это незаметно. Что еще более важно, поскольку у вас есть 300 000 пользователей, тогда некоторые из ваших значений StaffNumber должны быть не менее шести цифр, и в зависимости от того, как отформатирован CSV (StaffNumber с нулевым количеством до максимального количества цифр?) И отсортировано, возможно, вы может совпадать с неправильным пользователем. Например, если $inputNumber - 12345, то он будет соответствовать пользователю 12345, но также и пользователям 112345 и 123450. Если вы намерены разрешить поиск только точным номером штата, то переключение на -eq или решение HashTable выше выполнит это.

Смежные вопросы