快速比较 powershell 中的两个大 csv(行和列)
Fast compare two large csv(boths rows and columns) in powershell
我有两个大型 CSV 文件要比较。 Bosth csvs 基本上是相隔 1 天来自同一系统的数据。行数约为 12k,列数约为 30。
目的是确定主键(#ID)的哪些列数据发生了变化。
我的想法是遍历 CSV 以识别哪些行已更改并将它们转储到单独的 csvs 中。完成后,我再次遍历更改行,并确定列中的确切更改。
NewCSV = Import-Csv -Path ".\Data_A.csv"
OldCSV = Import-Csv -Path ".\Data_B.csv"
foreach ($LineNew in $NewCSV)
{
ForEach ($LineOld in $OldCSV)
{
If($LineNew -eq $LineOld)
{
Write-Host $LineNew, " Match"
}else{
Write-Host $LineNew, " Not Match"
}
}
}
但是一旦 运行 循环,就需要永远 运行 12k 行。我希望必须有一种更有效的方法来比较大文件 powershell。更快的东西。
好吧,你可以试一试,我并不是说 已经指出的内容会很快,但它应该给你一个很好的并排视角来比较已经指出的内容从 OldCsv 更改为 NewCsv。
注意:那些在两个 CSV 上具有相同值的单元格将被忽略。
$NewCSV = Import-Csv -Path ".\Data_A.csv"
$OldCSV = Import-Csv -Path ".\Data_B.csv" | Group-Object ID -AsHashTable -AsString
$properties = $newCsv[0].PSObject.Properties.Name
$result = foreach($line in $NewCSV)
{
if($ref = $OldCSV[$line.ID])
{
foreach($prop in $properties)
{
if($line.$prop -ne $ref.$prop)
{
[pscustomobject]@{
ID = $line.ID
Property = $prop
OldValue = $ref.$prop
NewValue = $line.$prop
}
}
}
continue
}
Write-Warning "ID $($line.ID) could not be found on Old Csv!!"
}
作为 ,您编写了一个具有 二次 时间复杂度(O(n²)
Big-O 表示法)的算法 - 每次输入大小翻倍,执行的计算量增加 4 倍。
为避免这种情况,我建议使用哈希表或其他字典类型来保存每个数据集,并使用输入中的主键作为字典键。通过这种方式,您可以获得相应记录的恒定时间查找,并且您的算法的时间复杂度变得接近线性(O(2n + k)
):
$NewCSV = @{}
Import-Csv -Path ".\Data_A.csv" |ForEach-Object {
$NewCSV[$_.ID] = $_
}
$OldCSV = @{}
Import-Csv -Path ".\Data_B.csv" |ForEach-Object {
$OldCSV[$_.ID] = $_
}
现在我们可以通过 ID 有效地解析每一行,我们可以检查整个数据集,每个数据集都有一个独立的循环:
foreach($entry in $NewCSV.GetEnumerator()){
if(-not $OldCSV.ContainsKey($entry.Key)){
# $entry.Value is a new row, not seen in the old data set
}
$newRow = $entry.Value
$oldRow = $OldCSV[$entry.Key]
# do the individual comparison of the rows here
}
像上面一样做另一个循环,但是用 $NewCSV
代替 $OldCSV
到 find/detect 删除。
我有两个大型 CSV 文件要比较。 Bosth csvs 基本上是相隔 1 天来自同一系统的数据。行数约为 12k,列数约为 30。
目的是确定主键(#ID)的哪些列数据发生了变化。
我的想法是遍历 CSV 以识别哪些行已更改并将它们转储到单独的 csvs 中。完成后,我再次遍历更改行,并确定列中的确切更改。
NewCSV = Import-Csv -Path ".\Data_A.csv"
OldCSV = Import-Csv -Path ".\Data_B.csv"
foreach ($LineNew in $NewCSV)
{
ForEach ($LineOld in $OldCSV)
{
If($LineNew -eq $LineOld)
{
Write-Host $LineNew, " Match"
}else{
Write-Host $LineNew, " Not Match"
}
}
}
但是一旦 运行 循环,就需要永远 运行 12k 行。我希望必须有一种更有效的方法来比较大文件 powershell。更快的东西。
好吧,你可以试一试,我并不是说
注意:那些在两个 CSV 上具有相同值的单元格将被忽略。
$NewCSV = Import-Csv -Path ".\Data_A.csv"
$OldCSV = Import-Csv -Path ".\Data_B.csv" | Group-Object ID -AsHashTable -AsString
$properties = $newCsv[0].PSObject.Properties.Name
$result = foreach($line in $NewCSV)
{
if($ref = $OldCSV[$line.ID])
{
foreach($prop in $properties)
{
if($line.$prop -ne $ref.$prop)
{
[pscustomobject]@{
ID = $line.ID
Property = $prop
OldValue = $ref.$prop
NewValue = $line.$prop
}
}
}
continue
}
Write-Warning "ID $($line.ID) could not be found on Old Csv!!"
}
作为 O(n²)
Big-O 表示法)的算法 - 每次输入大小翻倍,执行的计算量增加 4 倍。
为避免这种情况,我建议使用哈希表或其他字典类型来保存每个数据集,并使用输入中的主键作为字典键。通过这种方式,您可以获得相应记录的恒定时间查找,并且您的算法的时间复杂度变得接近线性(O(2n + k)
):
$NewCSV = @{}
Import-Csv -Path ".\Data_A.csv" |ForEach-Object {
$NewCSV[$_.ID] = $_
}
$OldCSV = @{}
Import-Csv -Path ".\Data_B.csv" |ForEach-Object {
$OldCSV[$_.ID] = $_
}
现在我们可以通过 ID 有效地解析每一行,我们可以检查整个数据集,每个数据集都有一个独立的循环:
foreach($entry in $NewCSV.GetEnumerator()){
if(-not $OldCSV.ContainsKey($entry.Key)){
# $entry.Value is a new row, not seen in the old data set
}
$newRow = $entry.Value
$oldRow = $OldCSV[$entry.Key]
# do the individual comparison of the rows here
}
像上面一样做另一个循环,但是用 $NewCSV
代替 $OldCSV
到 find/detect 删除。