【发布时间】:2021-05-19 19:52:03
【问题描述】:
(这可能是我想念的相当简单的东西;但我似乎无法弄清楚,也没有在搜索中找到任何答案)
我需要比较两个相同列的 CSV 文件,并输出行差异如下(最终输出为 Unicode 文本):
- 如果 FileA 中存在行但 FileB 中不存在行,则将该行标记为“Good”
- 如果 FileB 中存在行但 FileA 中不存在行,则将该行标记为“Bad”
假设我有以下示例数据:
File A:
Column1,Column2,Column3
Tommy,4133,20180204
Suzie,5200,20210112
Tammy,221,20201010
File B:
Column1,Column2,Column3
Tommy,4133,20180204
Nicky,5200,20190520
这是我当前的代码(借用 the hash-enabled Compare-Object2 from this site,因为交付的 Compare-Object 太慢了——仅供参考,我使用 Get-Content 而不是 Import-Csv,因为它快了 50 倍,因为我们是比较整行。而 MyHeader 变量只是为了保留原始文件的标题列值)
Compare-Object2 (Get-Content $FileA) (Get-Content $FileB) -PassThru |
Select-Object @{l=[string]$MyHeader;e={$_.InputObject}},
@{n='Row Label'; e={ @{'=>' = 'Bad' ; '<=' = 'Good'}[$_.SideIndicator]}},
@{n='Placeholder'; e={@{'*'='0'}['*']}} |
Sort-Object 'Row Label' -Descending | Export-Csv "$FinalCSV" -NoType;
#Removing " char to create CSV with original and added columns together
Set-Content "$FinalCSV" ((Get-Content "$FinalCSV") -replace '"');
#Convert csv to tab delimited
Import-Csv "$FinalCSV" | Export-Csv "$FinalTXT" -NoTypeInformation -Delimiter "`t";
#Remove " char and convert to unicode
Set-Content -Encoding UNICODE "$FinalTXT" ((Get-Content "$FinalTXT") -replace '"')
这很好用(我知道其中一些在最后是多余的;但是嘿:这是我能做的最好的——但绝对也可以随意修复这些部分!)创建一个好的输出文件和坏的 - 两个 400K 行的文件大约需要 40 秒。
Result File:
Column1 Column2 Column3 Row Label Placeholder
Suzie 5200 20210112 Good 0
Tammy 221 20201010 Good 0
Nicky 5200 20210112 Bad 0
问题是,我现在需要将它们创建为单独的 文件:一个文件是好的,一个是坏的。所以新需要的输出是:
ResultFileGood:
Column1 Column2 Column3 Row Label Placeholder
Suzie 5200 20210112 Good 0
Tammy 221 20201010 Good 0
ResultFileBad:
Column1 Column2 Column3 Row Label Placeholder
Nicky 5200 20210112 Bad 0
而且我只知道必须有一种方法可以做到这一点,而不必运行两次比较 - 使用 Where-Object 道具或某种循环。我就是想不通;所以我要去找专家。
谢谢
编辑:感谢 postanote,一种可行的替代方法是仅输出组合文件,然后将其拆分,这绝对比运行整个比较例程两次要快。还是想看看有没有办法直接在比较导出中做,不用中间文件;但这绝对是一个可行的选择,也是我现在使用的选择
$FinalHeader = get-content "$FinalTXT" | Select -First 1
$BadOutput = Select-String -Path $FinalTXT -Pattern ('Bad 0')
$GoodOutput = Select-String -Path $FinalTXT -Pattern ('Good 0')
@($FinalHeader,$BadOutput.Line) | Out-File "$FinalBadTXT" -Encoding UNICODE;
@($FinalHeader,$GoodOutput.Line) | Out-File "$FinalGoodTXT" -Encoding UNICODE;
【问题讨论】:
-
使用 if/then 或 try/catch 写入两个不同的日志文件。此外,使您的代码有目的地可读。您为跟随您的人编写代码以及代码将在哪里执行;不是为了你自己或你的工作站。善待他人。 ;-}
-
如果您只在 fileA 和 fileB 上显示几行,那么在没有 Compare-Object 或您的自定义函数的情况下,可能有一种更快的方法来完成您正在做的事情。
-
谢谢大家——抱歉@postanote:因为我只发布了代码的摘录,为了空间的缘故,我把一些格式压缩了;但我会在以后的帖子中更好地格式化。我同意@SantiagoSquarzon;我当然对其他想法持开放态度——我承认我在这里不是专家!我还在帖子中添加了一些示例数据——输入和期望的输出。另外,让我知道直接在我的帖子中发布 Compare-Object2 函数(和变量?)是否更合适,而不是仅仅链接(我不确定什么是最好的/最适合论坛)跨度>