PowerShell -为csv中缺少的数据添加行

lymgl2op  于 2023-06-03  发布在  Shell
关注(0)|答案(3)|浏览(182)

CSV文件有一个按顺序显示日期的列。需要检查缺少的日期并为其添加空行。我能够得到缺少的日期,但无法弄清楚如何添加行来代替它们。

$f=(Get-Date -Day 1)
$c=(Get-Date)
$a=@()
for($i=f;$i -lt $c;$i=$i.AddDays(1)
{
$a+=$i.ToString("yyyy-mm-dd")
}

$csv=Import-Csv -Path ${FilePath} -Header "Date","Token"
$c=$csv[2..(csv.length-1)] | select "Date"
$col=@()
foreach($line in $c)
{
$properties=$line | Get-Member -MemberType Properties
for($i=0;$i -lt $properties.Count;$i++)
{
$column=$properties[$i]
$colvalue=$line | select -ExpandProperty $column.Name
$col=$col+columnvalue
}
}
$c= $a | ? {!($col -contains $_)}

输出-(当前日期7)

2023-05-01
2023-05-02
2023-05-03
2023-05-04
2023-05-05
2023-05-06
2023-05-07

从这里我得到了第一个到当前日期之间的缺失日期。如何在这些缺失日期应该在的位置添加行?
Csv文件看起来像这样-

Name
Date       Token
2023-05-01 663
2023-05-02 522
2023-05-05 663
2023-05-07 636

考虑到当前日期为第7个缺失日期,则为3、4和6。所以我需要文件看起来像这样-

Name
Date       Token
2023-05-01 663
2023-05-02 522
<row inserted>
<row inserted>
2023-05-05 663
<row inserted>
2023-05-07 636

编辑:所有的答案都有助于我了解如何在这方面工作,但似乎我的问题不清楚。我需要日期直到 * 当前日期 * 不是最后日期在csv文件。因此,如果今天是6月2日,我需要从本月1日到当前日期的所有缺失日期。

ktca8awb

ktca8awb1#

也许下面的内容会有所帮助,添加了内联注解来帮助您理解逻辑。

$csv = @'
Date,Token
2023-05-01,663
2023-05-02,522
2023-05-05,663
2023-05-07,636
'@ | ConvertFrom-Csv

$result = for($i = 0; $i -lt $csv.Count; $i++) {
    # $z: next Collection Index 
    # $x: next Date Index
    $z = $i + 1; $x = 0
    $current = $csv[$i]
    $date = [datetime]::Parse($current.Date, [cultureinfo]::InvariantCulture)
    $current
    # while there is a next item in this collection
    while($next = $csv[$z++]) {
        # increment the next Date Index
        $x++
        # parse the date of the next collection item
        $nextDate = [datetime]::Parse($next.Date, [cultureinfo]::InvariantCulture)

        # if the date of the current item + $x is equal to the next collection item date
        if($date.AddDays($x) -eq $nextDate) {
            # break this loop
            break
        }

        # else, output a new object using the $x Date Index
        [pscustomobject]@{
            Date  = $date.AddDays($x).ToString('yyyy-MM-dd')
            Token = $null
        }
    }
}

输出将变为:

Date       Token
----       -----
2023-05-01 663
2023-05-02 522
2023-05-03
2023-05-04
2023-05-05 663
2023-05-06
2023-05-07 636
ruyhziif

ruyhziif2#

为了补充Santiago SquarzonJosefZ提供的有用答案,使用PowerShell pipeline的版本占用的内存更少

$Csv = @'
Date,Token
2023-05-01,663
2023-05-02,522
2023-05-05,663
2023-05-07,636
'@
# Import-Csv -Path FilePath | ...
ConvertFrom-Csv $Csv |
    Foreach-Object -Begin { $Date = [DateTime]::maxvalue } -Process {
        $_Date = Get-Date($_.Date)
        while ($Date -lt $_Date) {
            [pscustomobject]@{
                Date  = $Date.ToString('yyyy-MM-dd')
                Token = $null
            }
            $Date = $Date.AddDays(1)
        }
        $_
        $Date = $_Date.AddDays(1)
    }
Date       Token
----       -----
2023-05-01 663
2023-05-02 522
2023-05-03
2023-05-04
2023-05-05 663
2023-05-06
2023-05-07 636
brtdzjyr

brtdzjyr3#

下面的代码片段可能会有所帮助:

$csvFileContent = @'
Date,Token
2023-05-01,663
2023-05-02,522
2023-05-05,663
2023-05-07,636
'@
$csvData = $csvFileContent | ConvertFrom-Csv -Delimiter ','
$csvDataNew = [System.Collections.ArrayList]::new()
foreach ($csvLine in $csvData) {
    if ( $csvDataNew.Count -eq 0) {
        [void]$csvDataNew.Add( $csvLine)
    } else {
        $csvDateNext = (Get-Date -Date $csvDataNew[-1].Date
            ).AddDays(1).ToString( 'yyyy-MM-dd')
        while ($csvLine.Date -gt $csvDateNext) {
            [void]$csvDataNew.Add(
                [PSCustomObject]@{
                    Date  = $csvDateNext
                    Token = $null
                }
            )
            $csvDateNext = (Get-Date -Date $csvDataNew[-1].Date
                ).AddDays(1).ToString( 'yyyy-MM-dd')
        }
        [void]$csvDataNew.Add( $csvLine)
    }
}

$csvDataNew

输出.\SO\76375843.ps1

Date       Token
----       -----
2023-05-01 663
2023-05-02 522
2023-05-03
2023-05-04
2023-05-05 663
2023-05-06
2023-05-07 636

甚至对未排序的输入也有效;考虑

$csvData = $csvFileContent | ConvertFrom-Csv -Delimiter ',' |
    Sort-Object -Property Date

更新

使用相同的算法,但输入受限,以匹配给定的标准;在下面的代码片段中

  • 部分注解的代码突变,以及
  • 稍微改变输入数据:
$csvFileContent = @'
Date,Token
2023-05-02,522
2023-06-02,222
2023-07-07,777
'@

$csvDateFirst= (Get-Date -Day 1).ToString( 'yyyy-MM-dd')
$csvDateLast = (Get-Date).ToString( 'yyyy-MM-dd')

# updated: restrict input to dates in given interval
$csvData = [System.Collections.ArrayList]@(
    $csvFileContent |
        ConvertFrom-Csv -Delimiter ',' |
        Where-Object {
            $_.Date -ge $csvDateFirst -and $_.Date -le $csvDateLast |
        Sort-Object -Property Date 
    })

# ensure that input contains both starting and ending dates
# BEGIN
if ($csvData.Count -eq 0 -or $csvDateFirst -lt $csvData[0].Date) {
    [void]$csvData.Insert(0, 
        [PSCustomObject]@{ Date = $csvDateFirst; Token = $null})
} elseif ($csvDateFirst -gt $csvData[-1].Date) {
    $csvData = [System.Collections.ArrayList]::new(
        @([PSCustomObject]@{ Date = $csvDateFirst; Token = $null}))
}
if ($csvDateLast -gt $csvData[-1].Date) {
    [void]$csvData.Add(
        [PSCustomObject]@{ Date = $csvDateLast; Token = $null})
}
# END

$csvDataNew = [System.Collections.ArrayList]::new()
foreach ($csvLine in $csvData) {
    if ( $csvDataNew.Count -eq 0) {
        [void]$csvDataNew.Add( $csvLine)
    } else {
        $csvDateNext = (Get-Date -Date $csvDataNew[-1].Date
            ).AddDays(1).ToString( 'yyyy-MM-dd')
        while ($csvLine.Date -gt $csvDateNext) {
            [void]$csvDataNew.Add(
                [PSCustomObject]@{
                    Date  = $csvDateNext
                    Token = $null
                }
            )
            $csvDateNext = (Get-Date -Date $csvDataNew[-1].Date
                ).AddDays(1).ToString( 'yyyy-MM-dd')
        }
        [void]$csvDataNew.Add( $csvLine)
    }
}

$csvDataNew

输出.\SO\76375843a.ps1

Date       Token
----       -----
2023-06-01      
2023-06-02 222  
2023-06-03

相关问题