Powershell 基于与第一列的匹配合并2个csv文件的更快方法

Powershell 基于与第一列的匹配合并2个csv文件的更快方法,powershell,powershell-3.0,Powershell,Powershell 3.0,目前, 我正在尝试合并两个csv文件。第一个文件大约有3000多行。第二个文件大约有40多万行 为了测试这一点,我使用了这两个 第一个csv文件: Csv1ColumnOne,Csv1ColumnTwo,Csv1ColumnThree,Csv1ColumnFour 1234,Value1,Value1,Value1 2345,Value2,Value1,Value1 3456,Value1,Value2,Value1 4567,Value1,Value1,Value2 7645,Value3,V

目前,

我正在尝试合并两个csv文件。第一个文件大约有3000多行。第二个文件大约有40多万行

为了测试这一点,我使用了这两个

第一个csv文件:

Csv1ColumnOne,Csv1ColumnTwo,Csv1ColumnThree,Csv1ColumnFour
1234,Value1,Value1,Value1
2345,Value2,Value1,Value1
3456,Value1,Value2,Value1
4567,Value1,Value1,Value2
7645,Value3,Value3,Value3
Csv2ColumnOne,Csv2ColumnTwo,Csv2ColumnThree
1234,abc,Value1
2345,asd,Value1
3456,qwe,Value1
4567,mnb,Value1
第二个csv文件:

Csv1ColumnOne,Csv1ColumnTwo,Csv1ColumnThree,Csv1ColumnFour
1234,Value1,Value1,Value1
2345,Value2,Value1,Value1
3456,Value1,Value2,Value1
4567,Value1,Value1,Value2
7645,Value3,Value3,Value3
Csv2ColumnOne,Csv2ColumnTwo,Csv2ColumnThree
1234,abc,Value1
2345,asd,Value1
3456,qwe,Value1
4567,mnb,Value1
最终结果文件应如下所示:

"Csv1ColumnOne","Csv1ColumnTwo","Csv1ColumnThree","Csv1ColumnFour","Csv2ColumnOne"
"1234","Value1","Value1","Value1","abc"
"2345","Value2","Value1","Value1","asd"
"3456","Value1","Value2","Value1","qwe"
"4567","Value1","Value1","Value2","mnb"
"7645","Value3","Value3","Value3","Not Found"
以下是我现在拥有的代码(目前正在使用):

对于以下行:

Import-Csv $secondFile | Where-Object {$firstColumnFirstFile -contains $_.'Csv2ColumnOne'} | ForEach-Object {$hashColumnOneColumnTwo2ndFile[$_.'Csv2ColumnOne'] = $_.Csv2ColumnTwo}

这大约需要30分钟(每列-每列10列)。这意味着在两个csv文件之间合并3000行大约需要5-7个小时(当我添加代码以在最终结果文件中添加其他列时)。有没有一种更快的方法可以从第二个超过400000行的文件中创建哈希表?

我不能百分之百地确定我是否理解了您的问题-但我针对您的测试文件运行了以下命令:

$file1 = Import-Csv .\file1.csv
$file2 = Import-Csv .\file2.csv

$file1 | ForEach-Object {
    $f1 = $_
    $f1 | Add-Member -MemberType NoteProperty -Name csv2columnone -Value "" 
    $file2 | ForEach-Object {
        if($f1.csv1columnone -eq $_.csv2columnone) {
            if($_.csv2columntwo -ne $null) {
                $f1.csv2columnone = $_.csv2columntwo
            }
        } 
    }
    if([String]::IsNullOrEmpty($f1.csv2columnone)) {
        $f1.csv2columnone = "Not found"
    }
    Write-Output $f1
} | ft
结果是:

    Csv1ColumnOne Csv1ColumnTwo Csv1ColumnThree Csv1ColumnFour csv2columnone
------------- ------------- --------------- -------------- -------------
1234          Value1        Value1          Value1         abc          
2345          Value2        Value1          Value1         asd          
3456          Value1        Value2          Value1         qwe          
4567          Value1        Value1          Value2         mnb          
7645          Value3        Value3          Value3         Not found    

运行measure命令(用于运行时间)导致运行时间为20毫秒。

查看这是否会更快地生成哈希表:

$ht = @{}
Get-Content test1.csv -ReadCount 1000 |
foreach { 
 $ht += convertfrom-stringdata $($_ -replace '"?(.+?)"?,"?(.+?)"?,.+','$1=$2' | out-string)
 }

好的,所以我的便携式计算器使用以下公式(知道file2大约有400000多行):
400000(实际文件中的行数)/5(测试文件中的行数)*20(运行5行所需的毫秒)/60(将秒转换为分钟)=26.67分钟
。所以,大约在我运行代码的同时…如果我错了,请告诉我,但这只会从400000行中获取1000行?我需要它来抓取所有400000条线。。。另一个危险是csv文件有时没有引号,这会破坏foreach循环中的
-replace…
。除此之外,这个逻辑似乎是合理的…@Fiddle-Freak-它将抓取所有400000行,但它将一次抓取1000行。处理整个文件将需要400次循环迭代和400次磁盘读取,而不是400000次,而无需一次性将整个文件读入内存。如果存在字段可能被引用或不被引用的可能性,那么修改正则表达式以使引用成为可选的,方法相当简单,只需在它们后面加上?量词。我使用该选项更新了脚本,但如果前两个字段中的任何一个也包含嵌入的逗号,则可能会导致脚本失败。了解,请稍后再试。非常感谢:)对迟来的回复表示歉意。我一直到凌晨3点才完成一个剧本。我用我的算法和你的算法测试了一个超过400000行的文件。时间结果如下:我的算法
00:09:18
,您的算法
00:07:36
。您可以尝试增加读取计数。我通常会发现最佳值在一次1000到10000条记录之间。到目前为止,我认为一个好的选择是创建文件2的第二个版本,其中只有在第1列文件1中找到匹配项时,才会填充行。从而得出创建哈希表(3000^3000)与(3000^400000)的公式。