【问题标题】:Powershell - Import CSV sort on Date and assign earliest date for each user IDPowershell - 按日期导入 CSV 排序并为每个用户 ID 分配最早日期
【发布时间】:2021-12-17 05:51:05
【问题描述】:

尝试导入具有 ID、开始日期、结束日期列的 CSV,其中每行可以包含相同的 ID 值但不同的日期。
想要对此进行排序,以便找到每个 ID 的最早日期同一 ID 的最新结束日期,然后将其写入 CSV。

输入 csv:

ID Start Date End Date
100 01-Apr-2021 23-May-2021
100 10-June-2021 30-Dec-2021
200 12-Aug-2021 23-Sep-2021
200 25-Dec-2021 24-May-2022

输出 csv:

ID Start Date End Date
100 01-Apr-2021 30-Dec-2021
200 12-Aug-2021 24-May-2022

我以为我可以导入 CSV,然后识别 ID,然后为每个 ID 排序开始和结束日期,但似乎无法正常工作。

到目前为止的代码:

$source = "C:\test\test.csv"
$outPut = "C:\test\Testsort.csv"

$csv = Import-Csv $source 
Foreach ($usr in $csv){
    $userID= $usr."ID"
    $filtered = $csv | Where-Object {($_.'ID') -eq $userID}
    $output = [pscustomobject]@{
                     'ID'  = $userID
                     'Start Date'   =($filtered.'Start Date' | Sort-Object @{Expression= 
                      {[datetime]($_."Start Date")};Descending=$false} | Select -First 1
                     'End Date'     =($filtered.'Start Date' | Sort-Object @{Expression= 
                      {[datetime]($_."End Date")};Descending=$True} | Select -Last 1
                     }
}
$output | Export-csv $outPut 

遗憾的是,我正在为每个 ID 的开始日期和结束日期排序以及为每个 ID 设置最早和最旧的值而苦苦挣扎。

有什么想法吗?

【问题讨论】:

    标签: arrays powershell sorting


    【解决方案1】:
    • 使用Group-Object cmdlet 按共享的ID 值对行进行分组。

    • 对于每组具有相同 ID 的行,在 Start Date 列中找到最早的日期,在 End Date 列中找到最新的日期,然后结合这些值构造一个输出 [pscustomobject]

    $source = "C:\test\test.csv"
    $output = "C:\test\Testsort.csv"
    
    Import-Csv $source | 
        Group-Object Id |
          ForEach-Object { 
            $earliestStart = [Linq.Enumerable]::Min([datetime[]] $_.Group.'Start Date')
            $latestEnd = [Linq.Enumerable]::Max([datetime[]] $_.Group.'End Date')
            [pscustomobject] @{
              ID = $_.Name
              'Start Date' = $earliestStart.ToString('dd-MMM-yyyy', [cultureinfo]::InvariantCulture)
              'End Date' = $latestEnd.ToString('dd-MMM-yyyy', [cultureinfo]::InvariantCulture)
            }
          } |
            Export-csv $output 
    

    注意:

    • 虽然使用Sort-Object 查找最早和最晚日期也是一种选择,但[System.Linq.Enumerable]::Min() 方法的性能更好并且需要更少的内存。

    • 注意使用 cast [datetime[]]strings 从 CSV 输入转换为 [datetime] 实例,以便找到 chronological 最小值/最大值正常工作。

    • 在输出时,最小。和最大。使用[datetime] 类型的.ToString() 方法将日期转换回所需的日期字符串 格式。

    【讨论】:

    • 嘿,一如既往的好答案。您能否向我指出[System.Linq.Enumerable] 可能有用的其他答案?我想了解更多。
    • 谢谢@SantiagoSquarzon。我将从 this answer 开始,它涵盖了 PowerShell 中的 LINQ 使用。
    • 谢谢!我通常从你的答案而不是官方文档中学到更多,呵呵
    • 听到这个消息我既高兴又难过,@Santiago :)
    • 哇,太酷了!我还有很多事情要做。快速的问题,日期输出 .ToString('dd-MMM-yyyy') 将日期写为 24-May.-2022 (在一个月之后放置一个句点)....有什么原因吗?
    【解决方案2】:

    利用 group-object 和自定义属性,你可以用单线做到这一点:

    $source = "C:\test\test.csv"
    $outPut = "C:\test\Testsort.csv"
    $csv = Import-Csv $source 
    $csv|group-object id|select name,@{l='start date';e={$_.group|sort "Start Date"|select -expand "Start Date" -first 1 }},@{l='end date';e={$_.group|sort "end Date"|select -expand "end Date" -last 1 }}|Export-csv $outPut 
    

    【讨论】:

    • 这很有希望,但请注意,从 CSV 读取的日期值是字符串,因此默认情况下不会按时间顺序排序。另外,为了便于阅读,我是否可以建议将您的解决方案分散到多行? (您仍然可以将其作为单个 管道 执行,如果您以 | 结束每一行,则不需要反引号来继续行。
    • 我注意到了同样的事情(字符串日期值)。它似乎“有点”工作,但在使用具有 1100 行 ID(4-5 个重复 ID)的较大文件时不会将开始日期升序放置您是否必须将其扩展为类似:@{l='Start Date';e={[datetime]($_.group)|sort "Start Date" |select -expand "Start Date" -first 1 }}
    • @Mr80s、$_.Group | Sort-Object { [datetime] $_.'Start Date' }$_.Group | Sort-Object { [datetime] $_.'End Date' } 应该可以。
    • @mklement0 谢谢!工作
    猜你喜欢
    • 1970-01-01
    • 2016-12-18
    • 2018-04-16
    • 2021-08-11
    • 2018-04-15
    • 2020-07-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多