此代码返回两个文件之间的唯一和共享行。不幸的是,如果文件有100万行,它会永远运行。是否有更快的方法(例如-eq, -match, wildcard, Compare-Object)或遏制运算符是最佳方法?
$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
答案 0 :(得分:1)
正如我在回答您之前的问题时提到的,-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 = Get-Content (Read-Host "Enter 'A' file")
$ahash = @{}
$afile | ForEach-Object {
$ahash[$_] = $true
}
并处理这样的文件:
$afile | Where-Object {
-not $bhash.ContainsKey($_)
} | Set-Content 'lines_ONLY_in_A.txt'
如果仍然没有帮助,您需要确定瓶颈(读取文件,比较数据,进行多重比较,......)并从那里开始。
答案 1 :(得分:0)
试试这个:
$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
}
}
答案 2 :(得分:0)
考虑到我建议binary search的建议,我为此创建了一个可重复使用的Search-SortedArray
函数:
Search
(别名$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
。
$afile |? { $bfile -notcontains $_ }
注1 :由于开销,二进制搜索只会带来(非常)大数组的优势。
注2 :必须对数组进行排序,否则结果将无法预测。
Nate 3 :搜索没有考虑重复。如果有重复值,则只返回一个索引(这不是该特定问题的关注点)
根据@Ansgar Wiechers的评论添加2017-11-07:
快速基准测试,包含2个文件,每个文件有几千行(包括重复行):二进制搜索:2400ms; compare-object:1850ms;哈希表查找:250ms
这个想法是binary search从长远来看会占据优势:数组越大,它的比例增益就越大。
以$bfile
为例,评论中的表现测量和“几千行”是3000行:
$bfile
: * 1 平均需要1500次迭代
(3000 + 1) / 2 = 3001 / 2 = 1500
$afile
中平均需要6.27次迭代:
(log2 3000 + 1) / 2 = (11.55 + 1) / 2 = 6.27
在这两种情况下,您都会执行3000次(对于250ms / 1500 / 3000 = 56 nanoseconds
中的每个项目)
这意味着每次迭代都需要:
2400ms / 6.27 / 3000 = 127482 nanoseconds
盈亏平衡点将在约:
56 * ((x + 1) / 2 * 3000) = 127482 * ((log2 x + 1) / 2 * 3000)
根据我的计算,大约 40000 条目。
* 1假设哈希表查找本身不进行二进制搜索,因为它不知道数组已排序
已添加2017-11-07
评论中的结论:哈希表似乎具有类似的associative array算法,这些算法无法通过低级编程命令表现出色。
答案 3 :(得分:0)
最佳选择的完整代码(@ ansgar-wiechers)。唯一的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'