有没有一种方法可以提高Where-Obeject
的比较。在两个文件中都有1000条记录的情况还可以,但是当文件超过500k时,记录的速度确实很慢。
function progressBar ($i, $totalItems) {
Write-Progress -Activity "My Progress Bar" -Status "Doing stuff on $s" -PercentComplete ($i / $totalItems * 100)
}
$PSDefaultParameterValues['*:Encoding'] = 'utf8'
$f1 = (Import-Csv 'A.txt' -Delimiter 'µ' -Header samname, id)
$f2 = (Import-Csv 'B.txt' -Delimiter 'µ' -Header samname, id)
$counter = 0
$totalItems = $f1.Count
$f1 | ForEach-Object {
$samname = $_.samname
if ($m = $f2 | Where-Object {$_.samname -eq $samname}) {
$_.id = $m.id
} else {
$_.id = $_.id
}
$counter += 1
#Start-Sleep -s 3
progressbar -i $counter -totalItems $totalItems
}
$f1 | Export-Csv 'D.txt' -NoType
答案 0 :(得分:5)
通过Where-Object
语句中的ForEach-Object
子句,您正在有效地创建一个嵌套循环,这意味着该脚本进行了2500亿次比较。>
我通常要做的是将数组之一转换为哈希表,其中的键是您要比较的属性的值,然后将其用作“查找表”。
与遍历整个数组相比,通过键访问哈希表的速度超级快,因此比您当前的方法要快得多:
$f1=(import-csv 'A.txt' -Delimiter 'µ' -header samname,id)
$f2=(import-csv 'B.txt' -Delimiter 'µ' -header samname,id)
$h2 = @{}
$f2 |ForEach-Object {
$h2[$_.samname] = $_
}
$f1 |Foreach-object{
$samname=$_.samname
if($h2.ContainsKey($samname)){
$_.id = $h2[$samname].id
}
$counter += 1
#Start-Sleep -s 3
progressbar -i $counter -totalItems $totalItems
}
答案 1 :(得分:2)
正如Mathias R.Jessen所说,您要为第一组中的每条记录重复一次第二记录集。应该用更快的算法代替-如果对记录集进行排序,则使用哈希联接或合并联接。其次,Write-Progress
方法非常慢。尽量不要在每次迭代时都更新进度。您可以尝试此优化版本:
#demo data
(1..100000 | % { "Name_$($_)µ$($_)" }) -join "`n" | out-file A.txt
(1..100000 | % { "Name_$($_)µ$($_)" }) -join "`n" | out-file B.txt
$f1=(import-csv 'A.txt' -Delimiter 'µ' -header samname,id)
$f2=(import-csv 'B.txt' -Delimiter 'µ' -header samname,id)
$dict = @{}
$f2 | % {$dict[$_.samname] = $_.id}
$f1| % {
if ($dict.ContainsKey($_.samname)){
$_.id=$dict[$_.samname].id
} else {
$_.id = $_.id
}
#update every 100 iterations
if ($counter++%100 -eq 0) { progressbar -i $counter -totalItems $totalItems }
}
答案 2 :(得分:0)
如果您试图在两个具有相同“ samname”属性的csv文件之间获取对象,则可能需要考虑使用compare-object,例如:
比较对象-引用对象$ f1-差异对象$ f2-属性samname -IncludeEqual
如果您想弄乱管道上的这些对象,请使用-passthru
答案 3 :(得分:0)
无论如何您都违反了PowerShell pipeline技术,我会考虑使用.Where({...})
(PSv4 +)方法,该方法占用大量内存,但通常速度更快。
如果您确实想快速连接对象,则可以考虑使用Linq
,如RamblingCookieMonster的https://github.com/ili101/Join-Object示例一样。