【问题标题】:Powershell, Modify CSV field based on other field in same CSVPowershell,根据同一CSV中的其他字段修改CSV字段
【发布时间】:2020-10-14 05:58:58
【问题描述】:

我一直在努力寻找一种比多个 foreach 循环更好的方法来修改大型(1000 多行)CSV 文件。

我有一个 CSV 文件:

Name,login,ID,MGRID,MGRNAME
Bob Smith,bsmith,101,201,Drake Suzy
Suzy Drake,sdrake,201,300,Long Jane
John Bass,jbass,102,201,Drake Suzy
Jane Long,jlong,300,300,Long Jane

我正在尝试找到导入 csv 的最佳方法,然后为每个员工设置 MGRNAME 以匹配相应 MGR 的登录名。我想看看:

Name,login,ID,MGRID,MGRNAME
Bob Smith,bsmith,101,201,sdrake
Suzy Drake,sdrake,201,300,jlong
John Bass,jbass,102,201,sdrake
Jane Long,jlong,300,300,jlong

我已尝试导入 csv,然后使用以下方法替换 MGRNAME:

$Sup = Import-Csv $Csvfile
Foreach ($MGR in $SUP){
$SUP1 = $MGR.MGRId
$SupID = ($sup | Where-Object {$_.login -eq $Sup1}).Login
    Foreach ($ID in $Sup) {
      ($Sup | Where-Object {$_.MGRID -eq $SupID}).MGRNAME = $supId
    }

}

我也尝试过使用类似的东西:

$Users = Import-Csv $Csvfile
Foreach ($MGR in $users){
$supID=$MGR.MGRID
$RowIndex=[array]::Indexof($MGR.MGR.NAME,"$supID")
}

欢迎任何有用的建议。 谢谢

【问题讨论】:

  • 您的 CSV 格式似乎不太正确。你的分隔符是什么?如果是空格,它会弄乱你的数据,因为它们没有用引号括起来。你确定你的Import-CSV 真的有效吗?您需要为其指定尚未完成的标题和分隔符。见get-help import-csv
  • 这是逗号。我把它隔开以便于查看,但数据是名称、登录名、id、mgrid、mgrname 等。
  • 您的完整import-csv 命令是什么?记得引用你的项目,"name","login","id","etc."
  • 请将“易于阅读”的假 CSV 替换为真实的。这使人们无需手动编辑即可使用您的测试数据。 [咧嘴]

标签: arrays powershell csv indexing replace


【解决方案1】:

这是完成工作的一种方法。 [grin] 它做了什么...

  • 在 CSV 中伪造阅读
    当准备好使用真实数据执行此操作时,将整个 #region/#endregion 替换为对 Import-Csv 的调用。
  • 遍历导入的列表
  • 如果当前用户ID与MgrId相同,则设置MgrName为当前登录
  • 否则,使用mode 设置为First.Where({}) 方法调用查找Mgr,并使用生成的登录名设置MgrName
  • 显示结果

如果导入.Where({}) 查找可能会很慢。如果是这样,您可能会用哈希表替换它以进行查找。但是,过早的优化是不好的编码,所以我没有这样做。 [咧嘴一笑]

另外,导出到 CSV 的文件似乎有据可查,所以我没有包括在内。

代码...

#region >>> fake reading in a CSV file
#    in real life, use Import-CSV
$UserList = @'
Name,login,ID,MGRID,MGRNAME
Bob Smith,bsmith,101,201,Drake Suzy
Suzy Drake,sdrake,201,300,Long Jane
John Bass,jbass,102,201,Drake Suzy
Jane Long,jlong,300,300,Long Jane
'@ | ConvertFrom-Csv
#endregion >>> fake reading in a CSV file

foreach ($UL_Item in $UserList)
    {
    if ($UL_Item.Id -eq $UL_Item.MgrId)
        {
        $UL_Item.MgrName = $UL_Item.Login
        }
        else
        {
        $UL_Item.MgrName = $UserList.Where({$_.Id -eq $UL_Item.MgrId}, 'First', 1).Login
        }
    }

$UserList |
    # remember - DO NOT use the "Format-*" cmdlets for anything other than _final output as plain text_ [*grin*] 
    Format-Table

输出...

Name       login  ID  MGRID MGRNAME
----       -----  --  ----- -------
Bob Smith  bsmith 101 201   sdrake 
Suzy Drake sdrake 201 300   jlong  
John Bass  jbass  102 201   sdrake 
Jane Long  jlong  300 300   jlong

【讨论】:

  • 我会在你的 where() 方法中使用 First 模式。
  • @AdminOfThings - 噢噢! [grin] 我一直忘记那些在那里......谢谢你的提醒 - 补充说。
  • 这正是我的想法!谢谢你们。
  • @user2635212 - 不客气!很高兴能帮上忙……[grin]
【解决方案2】:

在 PowerShell 中加入对象是一项非常常见的活动,因此我之前创建了一个 'Join-Object' cmdlet,我仍然通过添加功能以及使用哈希表(出于性能原因,如 @Lee_Dailey 提到的)和添加 来维护它自加入能力:

InnerJoin $UserList -on MgrId -eq id -discern '',MGR |
Select-Object Name, Login, ID, MGRID, MGRLogin | Format-Table

Name       login  ID  MGRID MGRlogin
----       -----  --  ----- --------
Bob Smith  bsmith 101 201   sdrake
Suzy Drake sdrake 201 300   jlong
John Bass  jbass  102 201   sdrake
Jane Long  jlong  300 300   jlong

请注意,列标题 MGRLogin 与您问题中的示例不完全匹配(实际上与员工 Name 和 - Login 标题不一致),但如果您真的想要相同的标题,您可能做:

InnerJoin $UserList -on MgrId -eq id -discern '',MGR |
Select-Object Name, Login, ID, MGRID, @{n='MGRName'; e={$_.MGRLogin}} | Format-Table

有关更多详细信息,请参阅嵌入式帮助 (Help Join-Object) 和 In Powershell, what's the best way to join two tables into one?

【讨论】:

    猜你喜欢
    • 2023-03-21
    • 2018-04-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-26
    相关资源
    最近更新 更多