2017-02-16 22 views
0

私はImport-CSVで生成されたオブジェクトの2つのpowershell配列を持っています。具体的には、1:nのように、現在、私はこのパターンを以下のよ関係:PowerShellのキーでオブジェクトの2つの大きな配列を一致させる最も速い方法

foreach ($line in $array1) { 
    $match=$array2 | where {$_.key -eq $line.key} # could be 1 or n results 
    ...# process here the 1 to n lines 
} 

、非常に効率的ではありません(両方のテーブルに多くの列を持っている)と私たちのニーズに受け入れられない時間を要しています。このマッチを行う最速の方法はありますか?

両方のデータソースはcsvファイルから取得されるため、Import-CSVではなく何かを使用することも歓迎します。 ありがとう

+0

実際には、Import-CSVを実行するのにかかる時間はあまり関係がありません。これは約7k行で10秒未満であるため、「ワンショット」です。 2つのpowershell変数がロードされると問題が発生します。where句で実行される一致は0.34秒かかります – Roberto

+0

$ array2をキーでグループ化してから、$ array1のキーを反復して対応する結果を列挙できません?私の推測では、グループオブジェクトはPowerShellで実装しようとしているものより速いが、私は間違っている可能性がある。 –

答えて

2

標準的な方法は、ハッシュテーブル(または他の言語の辞書/地図)を使用してデータをインデックスすることです。また

function buildIndex($csv, [string]$keyName) { 
    $index = @{} 
    foreach ($row in $csv) { 
     $key = $row.($keyName) 
     $data = $index[$key] 
     if ($data -is [Collections.ArrayList]) { 
      $data.add($row) >$null 
     } elseif ($data) { 
      $index[$key] = [Collections.ArrayList]@($data, $row) 
     } else { 
      $index[$key] = $row 
     } 
    } 
    $index 
} 

$csv1 = Import-Csv 'r:\1.csv' 
$csv2 = Import-Csv 'r:\2.csv' 

$index2 = buildIndex $csv2, 'key' 

foreach ($row in $csv1) { 
    $matchedInCsv2 = $index2[$row.key] 
    foreach ($row2 in $matchedInCsv2) { 
     # ........ 
    } 
} 

、あなたはスピードを必要とを行う/ながら、それは/ foreachのより何倍も遅いのですとして|パイプライン化を避けるため、大きなコレクションを反復処理する場合。実行コンテキストを作成すると内部の単純なコードと比較して非常に大きなオーバーヘッドが追加されるため、where {$_.key -eq $line.key}のようなScriptBlockで何も使用しないでください。

+0

優秀かつ完全な答え...私はいくつかのテストを行い、ここに結果を投稿します。ありがとう! – Roberto

+0

1つのファイルが他のファイルよりもかなり小さい可能性がある場合は、小さい方のインデックスを選択してさらに最適化することができます。おそらくファイルの長さをチェックすることによって。 –

+0

うわー!このテクニックを使った簡単なテストは1アイテムあたり170msから4msになります!!!!再度、感謝します – Roberto

関連する問題