【问题标题】:Find string in array Powershell V2.0在数组中查找字符串 Powershell V2.0
【发布时间】:2018-08-15 07:52:02
【问题描述】:

我遇到了在 PowerShell V5.0 中运行但在 V2.0 中无法运行的脚本的问题。

我需要比较两个 CSV 文件中的两列,并编辑一个 CSV 中的一个值(如果两个文件中都存在)。

这是一个有问题的例子。 $a 在 V5.0 中重命名为 1X,在 V2.0 中仍为 1。我尝试使用 Compare,但这并不能解决我的问题。不幸的是,不能在该特定机器上升级到 V5.0。您能提供的任何建议将不胜感激。

# create examples
$a = @()
$itema = New-Object PSObject
$itema | Add-Member -Type NoteProperty -Name 'ID' -Value '1'
$a += $itema

$b = @()
$itemb = New-Object PSObject
$itemb | Add-Member -Type NoteProperty -Name 'ID' -Value '1'
$b += $itemb

# problem
foreach ($value in $a) {
    $ID = $value.ID
    if ($b.ID -contains $ID) {$value.ID = $ID + "X"}
}

【问题讨论】:

    标签: powershell powershell-2.0 powershell-5.0


    【解决方案1】:

    PowerShell v2 不支持 member enumeration,这是您在此处使用的:

    $b.ID -contains $ID
    

    该功能是在 PowerShell v3 中引入的。

    在 PowerShell v2 中,$b.ID 尝试扩展 数组 $b 的属性 ID,这会产生一个空结果,因为数组对象没有这样的属性。 p>

    在 PowerShell v3 和更新版本中,$b.ID 尝试在数组 $b元素 上扩展属性 ID(如果数组对象本身没有该属性)。

    要使您的代码与 PowerShell v2 兼容,请更改以下内容:

    if ($b.ID -contains $ID) {$value.ID = $ID + "X"}
    

    进入这个:

    if (@($b | Select-Object -Expand ID) -contains $ID) {$value.ID = $ID + "X"}
    

    附录:

    出于性能原因,将 ID 列表仅在循环外展开一次并将其存储在单独的变量中是有意义的

    $id_list = @($b | Select-Object -Expand ID)
    

    然后在比较中使用该变量:

    if ($id_list -contains $ID) {$value.ID = $ID + "X"}
    

    如果您真的迫切需要性能,我建议您根据 ID 创建一个哈希表

    $id_list = @{}
    foreach ($e in $b) {
        $id_list[$e.ID] = $true
    }
    

    然后像这样进行比较:

    if ($id_list.ContainsKey($ID)) {$value.ID = $ID + "X"}
    

    哈希表查找比-contains 操作提供更好的性能,因为前者执行索引查找,而后者执行数组线性搜索。

    【讨论】:

      【解决方案2】:

      这是因为 Powershell 2.0 不支持让您从数组中的对象中选择多个同名属性的功能。

      在以后的 Powershell 版本中,$b.ID 将为您提供来自$b 中对象的所有ID 值的数组。在 Powershell 2.0 中这不会发生,$.ID$null,因为数组本身没有 ID 属性。

      你可以像这样提取数组:

      $known_IDs = $b | ForEach-Object { $_.ID }
      

      之后,这适用于 PowerShell 2.0:

      foreach ($item_a in $a) {
          if ($known_IDs -contains $item_a.ID) {
              $item_a.ID += "X"
          }
      }
      

      或者,作为管道:

      $a | Where-Object { $known_IDs -contains $_.ID } | ForEach-Object { $_.ID += "X" } 
      

      【讨论】:

      • 这是最快的解决方案。
      猜你喜欢
      • 2020-06-19
      • 2021-12-11
      • 2014-05-27
      • 2017-03-22
      • 2015-08-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多