在PowerShell中比较两个较大的文本数组

时间:2016-10-07 20:58:04

标签: arrays powershell

我有两个阵列,我想区分它们。我在COMPARE-OBJECT上取得了一些成功,但对于较大的阵列来说太慢了。在这个例子中,$ ALLVALUES和$ ODD是我的两个数组。

我曾经能够使用FINDSTR有效地做到这一点 恩。 FINDSTR / V /G:ODD.txt ALLVALUES.txt> EVEN.txt FINDSTR在2秒内完成了110,000个元素。 (甚至不得不从磁盘读取和写入)

我正在尝试回到FINDSTR性能,它会给我ALLVALUES.txt中与ODD.txt不匹配的所有东西(在这种情况下给我EVEN值)

注意:这个问题与ODD或EVEN无关,只是一个可以快速,直观地验证其工作正常的实际例子。

这是我一直在玩的代码。使用COMPARE-OBJECT,我的计算机上的FINDSTR为100,000秒,而2秒则为2秒。我认为在 PowerShell 中有更优雅的方法。谢谢你的帮助。

# -------  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 个答案:

答案 0 :(得分:5)

数组是对象,而不仅仅是findtr进程的简单文本blob 字符串数组的最快差异是.NET3.5 + HashSet.SymmetricExceptWith

$diff = [Collections.Generic.HashSet[string]]$a
$diff.SymmetricExceptWith([Collections.Generic.HashSet[string]]$b)
$diffArray = [string[]]$diff
对于使用您的数据的i7 CPU上的100k元素,

46 ms。

上面的代码省略了重复值,所以如果在输出中需要这些值,我想我们将不得不使用慢得多的手动枚举。

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 ms,比hashset慢8倍但比Compare-Object快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
            }
        }
    }
}

100k元素:比Compare-Object快20-28倍,以2100ms / 1460ms(未分类)完成 10k元素:快2-3倍,以210ms / 162ms(未分类)完成