2016-08-09 9 views
1

私はCSVファイルで読み込んだPowerShellスクリプトを持っています。特定の列の日付がパラメータの日付よりも大きい場合、その行を新しいファイルに出力します。Where-Object with complex evaluation

今のところ、私はCSVファイルを読んでからForEach-Objectにパイプします。行が "通過する"場合は、それをArraylistに保存します。その後、すべての行が処理されると、Arraylistを出力CSVファイルに出力します。私の開始CSVファイルは225MB以上で、このプロセスは遅いです。

フィルター機能を配管に追加して、通過する行だけが出力CSVに渡されるようにする方法はありますか?現在のWhere-Objectは、-like,-contains ...のようなものを使用していますが、より複雑な評価形式ではありません。どこにブロックを混乱することを停止するために、私は関数としてConvertToDateを追加しました

Import-Csv -Delimiter "`t" -Header $headerCounter -Path $filePath | 
    Select-Object -Skip(1) | 
    ForEach-Object { 
     #Skip the header 
     if($lineCounter -eq 1) 
     { 
      return 
     } 

     $newDate = if ([string]::IsNullOrEmpty($_.1) -eq $true) 
         { [DateTime]::MinValue } 
         else { [datetime]::ParseExact($_.1,”yyyyMMdd”,$null) } 

     $updateDate = if ([string]::IsNullOrEmpty($_.2) -eq $true) 
         { [DateTime]::MinValue } 
         else { [datetime]::ParseExact($_.2,”yyyyMMdd”,$null) } 

     $distanceDate = (Get-Date).AddDays($daysBack * -1) 

     if($newDate -gt $distanceDate -or $updateDate -gt $distanceDate ) 
     { 
      [void]$filteredArrayList.Add($_) 
     } 
    } 
    ... 
    $filteredArrayList | 
    ConvertTo-Csv -Delimiter "`t" -NoTypeInformation | 
    select -Skip 1 | 
    % { $_ -replace '"', ""} | 
    out-file $ouputFile -fo -en unicode -Append 
+0

どのようにあなたのcsvファイルは次のようになりますか? –

答えて

2

は、ベストプラクティスについては、私は以下の私のコードを持っています。

DistanceDateは1回計算されているように見えます。

ExportCsvは、パイプライン入力をファイルに書き込む小さな関数です。

私はそれをテストしていないので、私は幸運を得ていない限り、バグはかなりありそうです。

function ConvertToDate { 
    param(
     [String]$DateString 
    ) 

    if ($DateString -eq '') { 
     return [DateTime]::MinValue 
    } else { 
     return [DateTime]::ParseExact($DateString, ”yyyyMMdd”, $null) 
    } 
} 

filter ExportCsv { 
    param(
     [Parameter(Position = 1)] 
     [String]$Path 
    ) 

    $csv = $_ | ConvertTo-Csv -Delimiter "`t" | Select-Object -Last 1 
    $csv -replace '"' | Out-File $Path -Append -Encoding Unicode -Force 
} 

$distanceDate = (Get-Date).AddDays($daysBack * -1) 

Import-Csv -Delimiter "`t" -Header $headerCounter -Path $filePath | 
    Select-Object -Skip 1 | 
    Where-Object { (ConvertToDate $_.1) -gt $distanceDate -or (ConvertToDate $_.2) -gt $distanceDate } | 
    ExportCsv $OutputFile 
+0

ExportCsv関数はそのままでは機能しませんでした。元のコードセットに含まれていたcsv作成コードを追加しました。 "テスト"コードを別の機能に入れることは、魅力的な働きをしました。 –

0

確かに、パイプラインから値を受け取り、それにImport-Csvの結果をパイプする関数を追加するだけです。関数内で、現在の項目をフィルタリングするかどうかをチェックします。文字列リストを使用し、hで始まるすべての文字列をフィルタリングここでは簡単な例:

$x = @('hello', 'world', 'hello', 'tree') 


filter Filter-CsvByMyRequirements 
{ 
    Param(
     [Parameter(Mandatory=$true, 
        ValueFromPipeline=$true)] 
     $InputObject 
    ) 

    Process 
    { 
     if ($_ -match '^h.*') 
     { 
      $_ 
     } 
    } 
} 


$x | Filter-CsvByMyRequirements | Write-Host 

が出力:

hello 
hello 
+1

実際のフィルタ(フィルタはプロセスブロックのみを実装する関数)を作成することを検討してください。それはもっときれいでしょう。 –

+0

@ChrisDent:開始ブロックと終了ブロックを削除しました –

+0

フィルタフィルタ-CsvByMyRequirements {param(...)if($ _ -match '^ h。*'){$ _}} ' –