【问题标题】:Read a CSV file and Progressively AddUp the values of a Specific column in Powershell读取 CSV 文件并逐步添加 Powershell 中特定列的值
【发布时间】:2021-02-03 19:16:38
【问题描述】:

我想使用 powershell 脚本读取 CSV 文件中特定列的所有行。 然后逐步添加值直到当前行,然后在新列中更新总和。

例如:在下面的示例中,我想读取 COLUMNB 列中的所有值,然后逐步添加它并在 PROG_COLB 中更新它 同样,我想为 COLUMNC 做这件事

CSV 文件示例:

"RANK","COLUMNB","COLUMNC"
"5","510","10"
"4","500","60"
"3","120","100"
"0","600","200"
"-1","1000","40"

预期输出:

"RANK","COLUMNB","COLUMNC","PROG_COLB","PROG_COLC"
"5","510","10","510","10"
"4","500","60","1010","70"
"3","120","100","1130","170"
"0","600","200","1730","370"
"-1","1000","40","2730","410"

我尝试了几件事,但无法获得预期的输出,我能够读取特定列,并且设法将其放入哈希表中,然后我被卡住了。 任何关于如何解决这个谜题的建议都会有很大帮助。

$csv =Import-Csv .\stats.csv 
$hash_COLB = @{​​​​}​​​​
$hash_COLC = @{​​​​}​​​​
foreach($item in $csv)
{​​​​
[int]$prog_COLB=[int]$prog_COLB+[int]$item.COLUMNB
[int]$prog_COLC=[int]$prog_COLC+[int]$item.COLUMNC
$hash_COLB.add($item.RANK,$prog_COLB)
$hash_COLC.add($item.RANK,$prog_COLC)
}​​​​

$hash_COLB
$hash_COLC

【问题讨论】:

    标签: powershell


    【解决方案1】:

    您可以为 COLUMNB 和 COLUMNC 中的值的运行计数创建两个变量。

    $runningCount_B = 0
    $runningCount_C = 0
    $result = Import-Csv -Path 'D:\Test\sample.csv' | ForEach-Object {
        $runningCount_B += [int]$_.COLUMNB
        $runningCount_C += [int]$_.COLUMNC
        # output a new object with all columns from the original, and added running counts
        $_ | Select-Object *, @{Name = 'PROG_COLB'; Expression = {$runningCount_B}}, 
                              @{Name = 'PROG_COLC'; Expression = {$runningCount_C}}
    }
    
    # output on console screen
    $result | Format-Table -AutoSize
    
    # output to new CSV
    $result | Export-Csv -Path 'D:\Test\new_sample.csv' -NoTypeInformation
    

    输出为 CSV:

    "RANK","COLUMNB","COLUMNC","PROG_COLB","PROG_COLC"
    "5","510","10","510","10"
    "4","500","60","1010","70"
    "3","120","100","1130","170"
    "0","600","200","1730","370"
    "-1","1000","40","2730","410"
    

    【讨论】:

      【解决方案2】:

      最直接 (IMO) 且易于阅读的解决方案使用 ForEach-Object 迭代行并输出具有计算出的新行的 PSCustomObject

      $sumColB = 0
      $sumColC = 0
      
      $newCsv = $csv | ForEach-Object {
          $sumColB += $_.COLUMNB
          $sumColC += $_.COLUMNC
      
          # This is the output of this loop iteration. PowerShell automatically adds it to $newCsv.
          [PSCustomObject]@{
              RANK      = $_.RANK
              COLUMNB   = $_.COLUMNB
              COLUMNC   = $_.COLUMNC
              PROG_COLB = $sumColB
              PROG_COLC = $sumColC
          }
      }
      

      另一种方式是Select-Objectcalculated properties一起使用,可读性较差,但具有可重复使用的优势。

      Function Get-ColumnSum( [ref] $var, $columnName ) { 
          $var.Value += $_.$columnName   # Add the value of the column named by $columnName
          $var.Value                     # output
      }
      
      $sumB = 0
      $sumC = 0
      
      $newCsv = $csv | Select-Object *, 
                         @{ name = 'PROG_COLB'; expression = { Get-ColumnSum ([ref] $sumB) COLUMNB } }, 
                         @{ name = 'PROG_COLC'; expression = { Get-ColumnSum ([ref] $sumC) COLUMNC } }
      

      首先我们定义一个函数Get-ColumnSum,它将给定列的值累加到一个通过引用传递的变量中,并输出当前的总和。

      然后在Select-Object 调用中,我们从计算列的脚本块中调用此函数。

      由于 PowerShell 范围规则,必须通过引用传递变量。如果您在嵌套范围内修改变量,则只会修改该变量的副本。通过传递引用我们可以直接修改给定的变量。

      【讨论】:

        猜你喜欢
        • 2020-06-22
        • 2012-08-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-10-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多