首页 > 解决方案 > 从数组中删除“较小”条目

问题描述

我正在尝试修剪我拥有的一些文件。我将为您保存到目前为止我编写的野兽,并通过提供虚构代码使其保持简单。

让我们来看看这个数组:

[System.String[]]$Collection = 'Invitational.Gold.txt', 'Invitational.Bronze.txt', 'Invitational.Silver.txt', 'Olympics.Silver.txt', 'Olympics.Bronze.txt'

此时,我需要做三件事:

  1. 按比赛类型分组(邀请赛/奥运会
  2. 按奖牌类型按价值降序排列(金/银/铜
  3. 根据比赛类型,保留最高价值的奖牌,同时删除其他奖牌。

我的第一个想法是使用一些正则表达式:

$Collection[0] -match '^(.+)\.(bronze|silver|gold).txt'

我在[0]这里使用,所以我可以在不编写 foreach 的情况下对其进行测试。

以上将存储Invitational$Matches[1]Gold$Matches[2]

现在,我可以$Collection使用Where-Object. 但是后来我在第 3 步中遇到了问题。你看,如果我使用 foreach-construct,它会执行match3 次,找到 3 次金牌。而且由于它第一次删除了文件,因此在第二次和第三次运行时会产生错误。

那么有人可以解释我如何只能对每种匹配类型进行一次查找吗?换句话说:

  1. 它找到第一个文件:Invitational.Gold
  2. 它查看是否还有其他奖牌,Invitational并找到银牌和铜牌文件,将其删除。
  3. 它移动到内存中的下一个文件,Invitational.Bronze.txt 它查看是否还有其他奖牌,Invitational并找到银和金文件。它继续尝试再次删除铜牌和银牌,导致错误,因为它们已被删除。这就是我需要避免但无法避免的。

$Collections那么我将如何在避免重复代码块(每次操作后重新编写内容)的同时实现这一点?

我能想到的最简洁的解决方案是以某种方式使用 Group-Object 为每个匹配类型创建组,然后只处理每个组一次。但我不知道该怎么做。

编辑:我现在正在考虑这些方面:

$Result = $Collection | ForEach-Object -Process {
  $Null = $PSItem -match '^(.+)\.(bronze|silver|gold).txt'
  $Properties = @{
    'MatchType' = $Matches[1]
    'Object'    = $PSItem
  }
  New-Object -TypeName PSObject -Property $Properties
}
$Result | Group-Object -Property MatchType

现在我有一个可以使用的分组。我认为。我会耐心等待更好的/其他建议。

标签: powershell

解决方案


这就是我的想法。但可能有更快的方法......但是具体重复 100 次总共需要 36 毫秒......

 [System.String[]]$Collection = 'Invitational.Gold.txt', 'Invitational.Bronze.txt', 'Invitational.Silver.txt', 'Olympics.Silver.txt', 'Olympics.Bronze.txt'

$collectionToOrder = $null
$collectionToOrder = foreach ($item in $Collection) {
$order = $null

    if ($item -match "Invitational") {$order = "1" }
    if ($item -match "Olympics") {$order = "2" }
    if ($item -match "Gold") {$order += "a" }
    if ($item -match "Silver") {$order += "b" }
    if ($item -match "Bronze") {$order += "c" }

    [pscustomobject] @{Order=$order
                       list=$Item
                                            }


}

$collectionOrdered = $collectionToOrder | sort -property order
Remove-Variable collectionToOrder 
$collectionToDelete = ($collectionOrdered | where order -Match "1")[1..5]
$collectionToDelete += ($collectionOrdered | where order -Match "2")[1..5]
foreach ($item in $collectionToDelete) {remove-item $item.list}

可以稍微修改一下(取决于您想要的输出),但基本上我让第一组搜索要求添加了一个名为 Order 的属性,其值为 1,2 等……然后下一组添加到该属性a、b、c 等。您可以继续添加到文本中。这意味着它可能有第三或第四个理由添加到订单中。最后按顺序排序。问题是,如果它找到不同的匹配词(例如silver.gold.Olympics),它将有趣地添加到 order 属性中,但您的示例没有将此作为可能的问题。

添加了另一个部分以删除错误的文件。请注意,它会从当前工作目录中删除。

你可以在最后做一些事情,比如

foreach ($item in $collectionToDelete) {remove-item $folder\$item.list}

如果你在顶部设置一个 $folder 变量作为你工作的地方

太晚了,我重新写了它以不同的工作方式,它不在乎你用什么词......

 [System.String[]]$Collection =  'Invitational.Bronze.txt', 'Invitational.Silver.txt',  'Invitational.Gold.txt', 'Olympics.Bronze.txt', 'Olympics.Silver.txt'

foreach ($item in $Collection) {
    if ($item -match "Silver") {
        remove-item $item.replace('.Silver.txt','.Bronze.txt')
    } 
}

foreach ($item in $Collection) {
    if ($item -match "Gold") {
        remove-item $item.replace('.Gold.txt','.Silver.txt')
        remove-item $item.replace('.Gold.txt','.Bronze.txt')
    }
}

这越来越长了哈哈......无论如何我接受了你的回答,(这是天才)并简化了它......

[System.String[]]$Collection = 'Invitational.Gold.txt', 'Invitational.Bronze.txt', 'Invitational.Silver.txt', 'Olympics.Silver.txt', 'Olympics.Bronze.txt', 'World.Open.Silver.txt'

$Collection | ForEach-Object -Process {
  If ($PSItem -match 'Silver') {
    $name = ($_ -split 'Silver') -join 'Bronze'
    If ($Collection -contains $name) { "Removing: $Name" }
  } # If 'Silver'
} # ForEach-Object

$Collection | ForEach-Object -Process {
  If ($PSItem -match 'Gold') {
      $name = ($_ -split 'Gold') -join 'Silver'
      If ($Collection -contains $name) { "Removing: $Name" }
      $name = ($_ -split 'Gold') -join 'Bronze'
      If ($Collection -contains $name) { "Removing: $Name" }
  } # If 'Gold'
} # ForEach-Object

推荐阅读