2017-12-01 3 views
0

を加速:私は、以下の条件の下で一つにCSV形式で3つのテキストファイルを結合する必要があるテーブルの調整

価格表-1.TXTでテーブルCNET-製品 - ドを指すProductIDがあります.txt - ProductIDにも。 のcnet-product-de.txtMarketingTextIDは、のcnet-text-de.txtIDを指しています。

ここで、3つのファイルを1つのスクリプトでCSVファイルに結合します。 最後に、ProductID。説明;製造業者識別番号; NetPrice; NetRetailPrice +テキストはcnet-text-en.txtからアップロードする必要があります。

スクリプトは機能しますが、ダブルループと巨大なtxtファイル(300,000行まで)の原因は永遠に(8時間以上)必要です。 誰かがスクリプトをスピードアップする方法を知っていますか?私がネイティブスピーカーではないので、条件を理解していなければ、条件を尋ねるのをためらうことはありません。

#start timer 
$stopwatch = [System.Diagnostics.Stopwatch]::StartNew() 

#Declaration 
$temp = @() 
$merged = @() 

#clear existent txt 
Clear-Content -Path "C:\temp\ALSO\merged.txt" 

#read CSVs 
$csvprice = Import-csv -path "C:\temp\ALSO\pricelist-1.txt" -Delimiter ';' 
$csvtext = Import-Csv -path "C:\temp\ALSO\cnet-text-de.txt" -Delimiter "`t" 

#Read CSV/Group by MarketingTextID/delete multiple ProductID entries 
$PAMID = Import-Csv -path "C:\temp\ALSO\cnet-product-de\cnet-product-de.txt" -Delimiter "`t" | 
    Select-Object ProductID, MarketingTextID | 
    Group-Object ProductID | 
    ForEach-Object { 
    [PsCustomObject]@{ 
     ProductID  = $_.group.ProductID | Get-Unique 
     MarketingTextID = $_.Group.MarketingTextID -join ',' 
    } 
} 

#get a single row from $PAMID 
ForEach ($ID1 in $PAMID) { 

    #Split the MarketingTextIDs 
    $1 = $ID1.MarketingTextID.Split(",")[0] 
    $2 = $ID1.MarketingTextID.Split(",")[1] 
    $3 = $ID1.MarketingTextID.Split(",")[2] 
    $4 = $ID1.MarketingTextID.Split(",")[3] 

    #get a single row from $csvtext 
    foreach ($ID in $csvtext) { 

     #Comparison with the individual MarketingTextIDs and add to $temp variable 
     if (($ID.ID -eq $1) -Or ($ID.ID -eq $2) -Or ($ID.ID -eq $3) -Or ($ID.ID -eq $3)) { 
      $temp += $ID1 | Select-Object *, @{name = "Text"; expression = {$ID.Text}} 
      break 
     } 
     else { 
      continue 
     } 

    } 
} 

#Get a single row from $temp 
foreach ($tempid in $temp) { 

    #Declaration 
    $tid = $tempid.ProductID 
    $tmid = $tempid.MarketingTextID 
    $ttext = $tempid.Text 

    #Get a single row from $csvprice 
    foreach ($Price in $csvprice) { 

     #Comparison ProductIDs and add to $merged Variable 
     if ($Price.ProductID -eq $tid) { 
      $Price = $Price | select *, @{name = "MarketingTextID"; expression = {$tmid}} 
      $Price = $Price | select *, @{name = "Text"; expression = {$ttext}} 
      $merged += $Price 
      break 
     } 
     else { 
      continue 
     } 
    } 

} 
#Export to txt in UTF8 format 
$merged | Export-Csv -Path "C:\temp\Also\merged.txt" -Encoding UTF8 

#Exit and output timer 
$stopwatch.stop() 
Write-Host "The script took $($stopwatch.elapsed.totalminutes) minutes" 
+0

'Join-Object'コマンドレットと' -contains'演算子を見てください。 – Clijsters

+0

私はJoin-Objectがおそらく行く方法であることに同意します。あなたがやろうとしていることは、SQLが非常に優れているようなリレーショナルジョインに似ています。ほとんどのデータベースシステムには、メインメモリにインデックス情報を作成することを含む、かなり効率的な戦略を見つけるオプティマイザが含まれています。あなたのアルゴリズムはブルートフォースのように見えます。あなたはこのような多くのデータを持っていると、そのようなことをすることはできません。 –

答えて

1

あなたは300000行のCSVを参加横断する必要がある場合、あなたは内側のループの300億回の繰り返しを見ています。それぞれが1ミリ秒以下でうまくいく場合でも、あなたは時間を見ています。

反復回数を減らす必要があります。そして現在、あなたはループの最後にcontinueをしています...そして、あなたは最初の結果だけを探します。だから、内側のループのみがこのように、単一の値を取得している:

foreach ($ID in $csvtext){ 
    if(($ID.ID -eq $1) -Or ($ID.ID -eq $2) -Or ($ID.ID -eq $3) -Or ($ID.ID -eq $3)) { 
    $temp += $ID1 | select *,@{name="Text";expression={$ID.Text}} 
    break 
    } else { 
    continue 
    } 
} 

はなれる:

$opts = $1, $2, $3, $4; 
$innerRes = $csvtext | Where-Object $_.ID -in $opts | 
      select-object -first 1 | 
      select-object *,@{name="Text";expression={$_.Text}} 

同様の外側のループに変換することで、結果にパイプラインを割り当てることができることを意味しますアレイに追加するのではなく(前者は後者よりも速い)。

一般的には、プラットフォームのコアパラダイム(PowerShell:パイプライン)を使用すると、他の行のコアパラダイムを使用するよりも効果的です。

最後に、あなたのツールが間違っている場合があります:各CSVをデータベースにアップロードし、SQLを使用します(この種の操作のために設計されています)が、SQLではset操作を使用する必要があります命令コード。

+0

_一般的に[...] pipelines_私はこれが本当に好きです。私は、オブジェクト指向の振る舞いに補うことができると考えています。これは、分割操作の大量使用を時代遅れにするでしょう。 – Clijsters

関連する問題