Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/windows/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Windows 来自大文件的共享且唯一的行。最快的方法?_Windows_List_Powershell_Text - Fatal编程技术网

Windows 来自大文件的共享且唯一的行。最快的方法?

Windows 来自大文件的共享且唯一的行。最快的方法?,windows,list,powershell,text,Windows,List,Powershell,Text,此代码返回两个文件之间的唯一和共享行。不幸的是,如果文件有一百万行,它将永远运行。是否有更快的方法来实现这一点,例如,或者安全壳操作员是最佳方法 $afile = Get-Content (Read-Host "Enter 'A' file") $bfile = Get-Content (Read-Host "Enter 'B' file") $afile | ? { $bfile -notcontains $_ } | Set-Content lines_ONLY_in_A.txt

此代码返回两个文件之间的唯一和共享行。不幸的是,如果文件有一百万行,它将永远运行。是否有更快的方法来实现这一点,例如,或者安全壳操作员是最佳方法

$afile = Get-Content (Read-Host "Enter 'A' file")
$bfile = Get-Content (Read-Host "Enter 'B' file")

$afile |
  ? { $bfile -notcontains $_ } |
  Set-Content lines_ONLY_in_A.txt

$bfile |
  ? { $afile -notcontains $_ } |
  Set-Content lines_ONLY_in_B.txt

$afile |
  ? { $bfile -contains $_ } |
  Set-Content lines_in_BOTH_A_and_B.txt
试试这个:

$All=@()
$All+= Get-Content "c:\temp\a.txt" | %{[pscustomobject]@{Row=$_;File="A"}}
$All+= Get-Content "c:\temp\b.txt" | %{[pscustomobject]@{Row=$_;File="B"}}
$All | group row | %{

$InA=$_.Group.File.Contains("A")
$InB=$_.Group.File.Contains("B")

if ($InA -and $InB)
{
    $_.Group.Row | select -unique | Out-File c:\temp\lines_in_A_And_B.txt -Append
}
elseif ($InA)
{
   $_.Group.Row | select -unique | Out-File c:\temp\lines_Only_A.txt  -Append
}
else
{
   $_.Group.Row | select -unique | Out-File c:\temp\lines_Only_B.txt -Append
}


}

正如我在回答您前面的一个问题时提到的,-contains是一个缓慢的操作,尤其是对于大型阵列

对于精确匹配,您可以使用Compare Object(比较对象)并按边指示器区分输出:

Compare-Object $afile $bfile -IncludeEqual | ForEach-Object {
    switch ($_.SideIndicator) {
        '<=' { $_.InputObject | Add-Content 'lines_ONLY_in_A.txt' }
        '=>' { $_.InputObject | Add-Content 'lines_ONLY_in_B.txt' }
        '==' { $_.InputObject | Add-Content 'lines_in_BOTH_A_and_B.txt' }
    }
}
并按如下方式处理文件:

$afile | Where-Object {
    -not $bhash.ContainsKey($_)
} | Set-Content 'lines_ONLY_in_A.txt'

如果这仍然不能帮助您确定读取文件、比较数据、进行多重比较的瓶颈。。。然后从这里开始。

考虑到我的建议,我已经为此创建了一个可重用的搜索函数:

描述 搜索排序Darray alias Search binary在排序数组中搜索字符串。如果找到字符串,则返回数组中找到的字符串的索引。否则,如果未找到字符串,则返回$Null

Function Search-SortedArray ([String[]]$SortedArray, [String]$Find, [Switch]$CaseSensitive) {
    $l = 0; $r = $SortedArray.Count - 1
    While ($l -le $r) {
        $m = [int](($l + $r) / 2)
        Switch ([String]::Compare($find, $SortedArray[$m], !$CaseSensitive)) {
            -1  {$r = $m - 1}
            1   {$l = $m + 1}
            Default {Return $m}
        }
    }
}; Set-Alias Search Search-SortedArray


$afile |
    ? {(Search $bfile $_) -eq $Null} |
    Set-Content lines_ONLY_in_A.txt

$bfile |
    ? {(Search $afile $_) -eq $Null} |
    Set-Content lines_ONLY_in_B.txt

$afile |
    ? {(Search $bfile $_) -ne $Null} |
    Set-Content lines_in_BOTH_A_and_B.txt
注1:由于开销,二进制搜索只能在非常大的数组中发挥优势

注意2:必须对数组进行排序,否则结果将不可预测

内特3:搜索没有发现重复的。在重复值的情况下,只返回一个索引,这与此特定问题无关

根据@Ansgar Wiechers的评论,增加了2017-11-07:


快速基准测试2个文件,每个文件有几千行,包括重复行:二进制搜索:2400ms;比较对象:1850ms;哈希表查找:250ms

其想法是,从长远来看,阵列将发挥其优势:阵列越大,其性能增益越高

拿了$afile |?{$bfile-notcontains$}例如,注释中的性能度量值和“几千行”是3000行:

对于标准搜索,在$B文件中平均需要1500次迭代:*1 在这两种情况下,对$afile中的每个项目执行此操作3000次 这意味着每次迭代需要:

对于标准搜索:250ms/1500/3000=56纳秒 对于二进制搜索:2400ms/6.27/3000=127482纳秒 盈亏平衡点大约为:

56 * ((x + 1) / 2 * 3000) = 127482 * ((log2 x + 1) / 2 * 3000) 根据我的计算,大约有40000个条目

*1假定哈希表查找本身不进行二进制搜索,因为它不知道数组已排序

2017年11月7日增补


从评论中得出的结论:哈希表似乎有一个类似的算法,在低级编程命令中无法超越

最佳选项的完整代码@ansgar wiechers。A唯一、B唯一和A、B共享行:

$afile = Get-Content (Read-Host "Enter 'A' file")
$ahash = @{}
$afile | ForEach-Object {
    $ahash[$_] = $true
}

$bfile = Get-Content (Read-Host "Enter 'B' file")
$bhash = @{}
$bfile | ForEach-Object {
    $bhash[$_] = $true
}

$afile | Where-Object {
    -not $bhash.ContainsKey($_)
} | Set-Content 'lines_ONLY_in_A.txt'

$bfile | Where-Object {
    -not $ahash.ContainsKey($_)
} | Set-Content 'lines_ONLY_in_B.txt'

$afile | Where-Object {
    $bhash.ContainsKey($_)
} | Set-Content 'lines_in _BOTH_A_and_B.txt'

这和你的另一个问题有关吗?这是一个独立的问题。您所指向的文件使用-match。如果对文件进行了排序,或者您保持了它们的排序,那么您可能需要执行一个喜欢二进制搜索策略的操作,我正在研究powershell或python解决方案。非常感谢。谢谢你们两位,@ansgar wiechers。我正在测试这些建议,并将向您汇报。谢谢。我需要一段时间才能回来报告,因为我正在用大文件测试这些选项;比较对象:1850ms;哈希表查找:250ms。谢谢,非常有用的信息。由于我的测量有限,哈希表似乎是最快的。仍在测试。@Ansgar Wiechers,感谢您的基准测试,假设“几千行”是3000行,我已经计算过,并在回答中解释了a在技术上应该在哪里以及如何在长期内获得超过标准搜索的优势。@iRon 250毫秒的标记来自哈希表方法。哈希表进行索引查找,而不是线性搜索,-contains运算符就是这样做的,这使得它非常慢,因此您永远不会达到收支平衡。相反,随着阵列大小的增加,差异将进一步增大。索引查找总是比二进制搜索快得多。 (log2 3000 + 1) / 2 = (11.55 + 1) / 2 = 6.27 56 * ((x + 1) / 2 * 3000) = 127482 * ((log2 x + 1) / 2 * 3000)
$afile = Get-Content (Read-Host "Enter 'A' file")
$ahash = @{}
$afile | ForEach-Object {
    $ahash[$_] = $true
}

$bfile = Get-Content (Read-Host "Enter 'B' file")
$bhash = @{}
$bfile | ForEach-Object {
    $bhash[$_] = $true
}

$afile | Where-Object {
    -not $bhash.ContainsKey($_)
} | Set-Content 'lines_ONLY_in_A.txt'

$bfile | Where-Object {
    -not $ahash.ContainsKey($_)
} | Set-Content 'lines_ONLY_in_B.txt'

$afile | Where-Object {
    $bhash.ContainsKey($_)
} | Set-Content 'lines_in _BOTH_A_and_B.txt'