/ / PowerShellでの2つの大きなテキスト配列の比較-配列、PowerShell

PowerShellの2つの大きなテキスト配列 - 配列、PowerShell

違いを取りたい2つの配列があります。 COMPARE-OBJECTである程度の成功を収めましたが、大きなアレイには遅すぎます。この例では、$ ALLVALUESと$ ODDが私の2つの配列です。

FINDSTRを使用してこれを効率的に行うことができました 例 FINDSTR / V /G:ODD.txt ALLVALUES.txt> EVEN.txt FINDSTRは、110,000個の要素について2秒未満でこれを完了しました。 (ディスクから読み書きする必要さえありました)

FINDSTRパフォーマンスに戻り、ODD.txtと一致しなかったALLVALUES.txtのすべてを取得しようとしています(この場合、EVEN値を提供しています)

注:この質問はODDやEVENに関するものではなく、目的どおりに機能していることを迅速かつ視覚的に確認できる実用的な例にすぎません。

これが私が遊んでいるコードです。 COMPARE-OBJECTを使用すると、コンピューター上のFINDSTRの場合、200,000秒に対して100,000時間かかりました。私はこれを行うにはもっとエレガントな方法があると考えています パワーシェル。ご協力いただきありがとうございます。

# -------  Build the MAIN array
$MIN = 1
$MAX = 100000
$PREFIX = "AA"

$ALLVALUES = while ($MIN -le $MAX)
{
"$PREFIX{0:D6}" -f $MIN++
}


# -------  Build the ODD values from the MAIN array
$MIN = 1
$MAX = 100000
$PREFIX = "AA"

$ODD = while ($MIN -le $MAX)
{
If ($MIN%2) {
"$PREFIX{0:D6}" -f $MIN++
}
ELSE {
$MIN++
}
}

Measure-Command{$EVEN = Compare-Object -DifferenceObject $ODD -ReferenceObject $ALLVALUES -PassThru}

回答:

回答№1は4

配列はオブジェクトであり、findstrが処理する単なるテキストの塊ではありません。
文字列配列の最速の差分は.NET3.5 +です HashSet.SymmetricExceptWith.

$diff = [Collections.Generic.HashSet[string]]$a
$diff.SymmetricExceptWith([Collections.Generic.HashSet[string]]$b)
$diffArray = [string[]]$diff

データを使用するi7 CPUの100k要素の場合は46ミリ秒。

上記のコードでは重複値が省略されているため、出力でそれらが必要な場合は、はるかに遅い手動列挙を使用する必要があると思います。

function Diff-Array($a, $b, [switch]$unique) {
if ($unique.IsPresent) {
$diff = [Collections.Generic.HashSet[string]]$a
$diff.SymmetricExceptWith([Collections.Generic.HashSet[string]]$b)
return [string[]]$diff
}
$occurrences = @{}
foreach ($_ in $a) { $occurrences[$_]++ }
foreach ($_ in $b) { $occurrences[$_]-- }
foreach ($_ in $occurrences.GetEnumerator()) {
$cnt = [Math]::Abs($_.value)
while ($cnt--) { $_.key }
}
}

使用法:

$diffArray = Diff-Array $ALLVALUES $ODD

340ミリ秒、ハッシュセットより8倍遅いが、比較オブジェクトより110倍速い!

そして最後に、文字列/数値の配列に対して、より高速なCompare-Objectを作成できます。

function Compare-StringArray($a, $b, [switch]$unsorted) {
$occurrences = if ($unsorted.IsPresent) { @{} }
else { [Collections.Generic.SortedDictionary[string,int]]::new() }
foreach ($_ in $a) { $occurrences[$_]++ }
foreach ($_ in $b) { $occurrences[$_]-- }
foreach ($_ in $occurrences.GetEnumerator()) {
$cnt = $_.value
if ($cnt) {
$diff = [PSCustomObject]@{
InputObject = $_.key
SideIndicator = if ($cnt -lt 0) { "=>" } else { "<=" }
}
$cnt = [Math]::Abs($cnt)
while ($cnt--) {
$diff
}
}
}
}

10万個の要素:Compare-Objectより20〜28倍高速で、2100ms / 1460msで完了(ソートなし)
10kエレメント:2-3倍高速、210ms / 162ms(未ソート)で完了