【问题标题】:Check csv file values against every line in another csv file对照另一个 csv 文件中的每一行检查 csv 文件值
【发布时间】:2020-05-19 16:33:20
【问题描述】:

我有两个包含数据的 csv 文件,我需要检查 CSV 1 中的值是否存在于 CSV 2 中,如果存在,则将 file2 中的值替换为 file1 中的数据,如果没有则跳到另一行,

文件1.csv

NO;Description
L001;DREAM
L002;CAR
L003;PHONE
L004;HOUSE
L005;PLANE

文件2.csv

ID;Name;Status*;Scheduled Start Date;Actual Start Date;Actual End Date;Scheduled End Date;SLA
144862;DREAM;Scheduled;1524031200;;;1524033000;
149137;CAR;Implementation In Progress;1528588800;;;1548968400;
150564;PHONE;Scheduled;1569456000;;;1569542400;
150564;HOUSE;Scheduled;1569456000;;;1569542400;
150564;PLANE;;;;;;

我尝试了类似的方法,但它不适合我:

    $file1 = Import-Csv "C:\Users\file1.csv" |Select-Object -ExpandProperty Description
$file2 = Import-Csv "C:\Users\file1.csv" |Select-Object -ExpandProperty NO
        Import-Csv "C:\Users\file3.csv" |Where-Object {$file1 -like $_.Name} |ForEach-Object {
          $_.Name = $file2($_.NO)
    } |Out-File "C:\Users\File4.csv"

File4.csv 应该是这样的:

ID;Name;Status*;Scheduled Start Date;Actual Start Date;Actual End Date;Scheduled End Date;SLA
144862;L001;Scheduled;1524031200;;;1524033000;
149137;L002;Implementation In Progress;1528588800;;;1548968400;
150564;L003;Scheduled;1569456000;;;1569542400;
150564;L004;Scheduled;1569456000;;;1569542400;
150564;L005;;;;;;

也许还有其他方法可以实现我的目标!谢谢

【问题讨论】:

  • 为什么Status 列中有星号?这是真的还是发帖时的错字?
  • 文件是这样导出的,不是拼写错误,但是这个列不是用来检查值的,所以我猜应该不是问题。

标签: powershell csv


【解决方案1】:

这是您可以采取的一种方法:

  • 使用Import-Csv 导入两个 CSV 文件
  • 从第一个 CSV 文件创建一个查找哈希表,其中要替换的 Description 是键,NO 是值。
  • 浏览第二个 CSV 文件,如果存在键,则替换散列表中 Name 列中的任何值。我们可以使用System.Collections.Hashtable.ContainsKey 来检查密钥是否存在。这是一个恒定时间O(1) 操作,因此查找速度很快。
  • 然后我们可以使用Export-Csv 导出最终的CSV。我使用-UseQuotes Never 在您的输出文件中没有添加" 引号。此功能仅在 PowerShell 7 中可用。对于较低的 PowerShell 版本,您可以查看 How to remove all quotations mark in the csv file using powershell script? 以了解从 CSV 文件中删除引号的其他替代方法。

演示:

$csvFile1 = Import-Csv -Path .\File1.csv -Delimiter ";"
$csvFile2 = Import-Csv -Path .\File2.csv -Delimiter ";"

$ht = @{}
foreach ($item in $csvFile1) {
    if (-not [string]::IsNullOrEmpty($item.Description)) {
        $ht[$item.Description] = $item.NO
    }
}

& {
    foreach ($line in $csvFile2) {
        if ($ht.ContainsKey($line.Name)) {
            $line.Name = $ht[$line.Name]
        }
        $line
    }
} | Export-Csv -Path File4.csv -Delimiter ";" -NoTypeInformation -UseQuotes Never

或者,我们可以使用Foreach-Object,而不是使用Call Operator &foreach 循环包装在脚本块中。您可以查看about_script_blocks 以获取有关脚本块的更多信息。

$csvFile2 | ForEach-Object {
    if ($ht.ContainsKey($_.Name)) {
        $_.Name = $ht[$_.Name]
    }
    $_
} | Export-Csv -Path File4.csv -Delimiter ";" -NoTypeInformation -UseQuotes Never

File4.csv

ID;Name;Status*;Scheduled Start Date;Actual Start Date;Actual End Date;Scheduled End Date;SLA
144862;L001;Scheduled;1524031200;;;1524033000;
149137;L002;Implementation In Progress;1528588800;;;1548968400;
150564;L003;Scheduled;1569456000;;;1569542400;
150564;L004;Scheduled;1569456000;;;1569542400;
150564;L005;;;;;;

更新

为了处理具有相同Name 的多个值,我们可以将上面的内容转换为使用System.Management.Automation.PSCustomObject 的哈希表,其中我们有两个属性Count 来跟踪我们正在查看的当前项目和@ 987654348@ 是一个数字数组:

$csvFile1 = Import-Csv -Path .\File1.csv -Delimiter ";"
$csvFile2 = Import-Csv -Path .\File2.csv -Delimiter ";"

$ht = @{}
foreach ($row in $csvFile1) {
    if (-not $ht.ContainsKey($row.Description) -and 
        -not [string]::IsNullOrEmpty($item.Description)) {
        $ht[$row.Description] = [PSCustomObject]@{
            Count = 0
            NO = @()
        }
    }
    $ht[$row.Description].NO += $row.NO
}

& {
    foreach ($line in $csvFile2) {
        if ($ht.ContainsKey($line.Name)) {
            $name = $line.Name
            $pos = $ht[$name].Count
            $line.Name = $ht[$name].NO[$pos]
            $ht[$name].Count += 1
        }
        $line
    }
} | Export-Csv -Path File4.csv -Delimiter ";" -NoTypeInformation -UseQuotes Never

【讨论】:

  • 我没有做错什么,但这部分对我不起作用$csvFile2 | ForEach-Object { if ($ht.ContainsKey($_.Name)) { $_.Name = $ht[$_.Name] } $_ } | Export-Csv -Path File4.csv -Delimiter ";" -NoTypeInformation -UseQuotes Never
  • @majan 你得到什么错误?对我来说很好。
  • 我的文件很大,有时在 File1.csv 的描述列中包含空值,如果没有值,有什么办法可以跳过。我对代码概率的第二个选项做错了
  • @majan 我添加了一项检查以确保没有$null 或使用[string]::IsNullOrEmpty 添加空值。仅当使用 ContainsKey$ht 中找到密钥时,才会更新第二个文件的行。
  • 好的,我有最后一次礼貌的请求,有时在 file1.csv 中我有多个相同描述的实例,但有另一个实例,NO;Description L001;DREAM L002;CAR L005;PLANE L011;DREAM L111;DREAM 现在只有第一次尝试添加到 file2,我怎么能添加每个尝试。最好的办法是复制整行并添加新 ID,如 ID;Name;Status*;Scheduled Start Date;Actual Start Date;Actual End Date;Scheduled End Date;SLA 144862;L001;Scheduled;1524031200;;;1524033000; 144862;L011;Scheduled;1524031200;;;1524033000; 144862;L111;Scheduled;1524031200;;;1524033000; 我希望你能明白
【解决方案2】:

如果你的文件不是太大,你可以用一个简单的 ForEach-Object 循环来做到这一点:

$csv1   = Import-Csv -Path 'D:\Test\File1.csv' -Delimiter ';'
$result = Import-Csv -Path 'D:\Test\File2.csv' -Delimiter ';' | 
          ForEach-Object {
              $name = $_.Name
              $item = $csv1 | Where-Object { $_.Description -eq $name } | Select-Object -First 1
              # update the Name property and output the item
              if ($item) { 
                $_.Name = $item.NO
                # if you output the row here, the result wil NOT contain rows that did not match
                # $_   
              }
              # if on the other hand, you would like to retain the items that didn't match unaltered,
              # then output the current row here
              $_
          }

# output on screen
$result | Format-Table -AutoSize

#output to new CSV file
$result | Export-Csv -Path 'D:\Test\File4.csv' -Delimiter ';' -NoTypeInformation

屏幕上的结果:

ID 名称 状态* 计划开始日期 实际开始日期 实际结束日期 计划结束日期 SLA -- ---- -------- -------------------- ----- --------------- ------------------ --- 144862 L001 预定 1524031200 1524033000 149137 L002 实施中 1528588800 1548968400 150564 L003 预定 1569456000 1569542400 150564 L004 预定 1569456000 1569542400 150564 L005

【讨论】:

  • 文件很大,但不知道但你的代码不起作用
  • @majan 它对我有用,但是在您的问题中,您从未解释过它涉及大文件。什么是“不工作”?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多