После работы с каждым из 3-х предоставленных ответов я создал рабочее решение в каждом случае, стараясь максимально приблизиться к решению, по-прежнему применяя его в своей ситуации.Вот что я придумал:
@ Кирилл Пашков представил концепцию веса / стоимости, с которой мне было очень интересно работать:
[System.String[]]$Collection = 'Invitational.Gold.txt', 'Invitational.Bronze.txt', 'Invitational.Silver.txt', 'Olympics.Silver.txt', 'Olympics.Bronze.txt', 'World.Open.Silver.txt'
$Weight = @{
'Gold' = 1;
'Silver' = 2;
'Bronze' = 3;
} # Weight
$DataSet = $Collection | ForEach-Object -Process {
$Null = $PSItem -match '^(.+)\.(bronze|silver|gold).txt'
$Properties = @{
'Type' = $Matches[1]
'Medal' = $Matches[2]
'Weight' = $Weight[$Matches[2]]
'Name' = $PSItem
} # Properties
New-Object -TypeName PSObject -Property $Properties
} # ForEach-Object
$DataSet | Group-Object -Property 'Type' | ForEach-Object -Process {
$PSItem.Group | Sort-Object -Property 'Weight' -Descending | Select-Object -SkipLast 1 | ForEach-Object -Process {
Write-Output -InputObject ('Removing: {0}' -f $PSItem.Name)
} # ForEach-Object
} # ForEach-Object
Вывод:
Removing: Invitational.Bronze.txt
Removing: Invitational.Silver.txt
Removing: Olympics.Bronze.txt
@ Lee_Dailey удалось получить Group-By
за одну строчку.Я не мог справиться с этим, но я использовал другие ответы, чтобы сократить его до трех строк.Затем мне пришлось реструктурировать полученную таблицу, чтобы отфильтровать ненужные файлы по их строковым значениям.И мне пришлось избегать групп, в которых был только один файл.Используя break
, я смог предотвратить повторяющиеся результаты из Switch
-выражения:
[System.String[]]$Collection = @(
'Invitational.Gold.txt'
'Invitational.Bronze.txt'
'Invitational.Silver.txt'
'Olympics.Silver.txt'
'Olympics.Bronze.txt'
'World.Open.Silver.txt'
) # $Collection
$DataSet = $Collection | ForEach-Object -Process {
$Null = $PSItem -match '^(.+)\.(bronze|silver|gold).txt'
[PSCustomObject] @{'Type' = $Matches[1]; 'Object' = $PSItem}
}
$GroupedCollection = $DataSet | Group-Object -Property 'Type'
ForEach ($Grouping in $GroupedCollection) {
If ($Grouping.Count -gt 1) {
$GP_Item = [PSCustomObject]@{'Name' = $Grouping.Name; 'Group' = ($Grouping.Group | Select-Object -ExpandProperty 'Object')}
Switch -Regex ($GP_Item.Group) {
'gold' {
"Keeping: $($GP_Item.Group -match 'gold')"
"Removing: $($GP_Item.Group -match 'silver')"
"Removing: $($GP_Item.Group -match 'bronze')"
Break
} # Gold
'silver' {
"Keeping: $($GP_Item.Group -match 'silver')"
"Removing: $($GP_Item.Group -match 'bronze')"
Break
} # Silver
} # Switch
} # If
} # ForEach
Вывод:
Keeping: Invitational.Gold.txt
Removing: Invitational.Silver.txt
Removing: Invitational.Bronze.txt
Keeping: Olympics.Silver.txt
Removing: Olympics.Bronze.txt
Наконец, у @Robert Cotterman было гениальное решение с использованием строкиманипуляции и RegEx, чтобы получить желаемый результат.Мне пришлось переписать, чтобы учесть, что тип совпадения неизвестен, но в конце удалось заставить его работать с большим использованием конвейера:
[System.String[]]$Collection = 'Invitational.Gold.txt', 'Invitational.Bronze.txt', 'Invitational.Silver.txt', 'Olympics.Silver.txt', 'Olympics.Bronze.txt', 'World.Open.Silver.txt'
[System.Int16]$Count = 1
$MatchTypes = $Collection | ForEach-Object -Process {
$Null = $PSItem -match '^(.+)\.(bronze|silver|gold).txt'
$Matches[1]
} | Select-Object -Unique | ForEach-Object -Process {
[PSCustomObject]@{'Name' = $PSItem; 'Order' = $Count}
$Count += 1
}
$CollectionToOrder = ForEach ($Item in $Collection) {
ForEach ($Type in $MatchTypes) { If ($Item -match $Type.Name) {[System.Int16]$Group = $Type.Order} }
Switch -Regex ($Item) {
'Gold' { $Weight = 'a' }
'Silver' { $Weight = 'b' }
'Bronze' { $Weight = 'c' }
} # Switch
[PSCustomObject]@{ 'Group' = $Group; 'Weight' = $Weight; 'List' = $Item }
} # ForEach
$CollectionOrdered = $CollectionToOrder | Sort-Object -Property 'Group', 'Weight' -Descending
[System.Int16]$TypeCount = ($CollectionOrdered | Select-Object -Property 'Group' -Unique).Count
$CollectionToDelete = 1..$TypeCount | ForEach-Object -Process { $CollectionOrdered | Where-Object -Property 'Group' -Match $PSItem | Select-Object -SkipLast 1 }
$CollectionToDelete | ForEach-Object -Process { Write-Output -InputObject ('Removing: {0}' -f $PSItem.List) }
Вывод:
Removing: Invitational.Bronze.txt
Removing: Invitational.Silver.txt
Removing: Olympics.Bronze.txt
Единственное, что меня раздражало, это то, что я не мог преобразовать свою -matches
строку в [regex]::match
строку, но это другой вопрос.Как и тот факт, что [PSCustomObject]
- это не то же самое, что [System.Management.Automation.PSCustomObject]
. В конце концов, я бы, вероятно, выбрал решение @Kirill Pashkov, так как оно кажется самым элегантным и позволяет мневозможно, заполните переменную Weight с помощью CSV (хотя тогда мне нужно будет также манипулировать запросом RegEx).Поэтому, если мой ответ не будет автоматически выбран в качестве принятого, я, скорее всего, выберу его.
Я потерял половину своих выходных, но я многому научился и теперь могу вернуться к работе над проектом манипулирования файловым сервером.Спасибо за помощь, ребята!
РЕДАКТИРОВАТЬ:
Попросите @Robert Cotterman придумать супер-простой способ сделать то, на что я потратил целый день.Просто идет, чтобы показать, что это не должно быть сложным.Я обнаружил, что split
-метод разделяется при каждом появлении каждого символа, но -split
-оператор использует RegEx и может работать с целым словом.Имея это в виду, а также возможность того, что что-то будет после медали, я все-таки получил это вместо replace
.
[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') {
$Split = $PSItem -split 'Silver'
$Name = ('{0}Bronze{1}' -f $Split[0], $Split[1])
If ($Collection -contains $Name) { "Removing: $Name" }
} # If
} # ForEach-Object
$Collection | ForEach-Object -Process {
If ($PSItem -match 'Gold') {
$Split = $PSItem -split 'Gold'
$Name = ('{0}Silver{1}' -f $Split[0], $Split[1])
If ($Collection -contains $Name) { "Removing: $Name" }
} # If
} # ForEach-Object
Вывод:
Removing: Invitational.Bronze.txt
Removing: Olympics.Bronze.txt
Removing: Invitational.Silver.txt
@ Последнее редактирование Роберта Коттермана помогло мне пересмотреть оператор -replace
.Также необходимо использовать elseif
, чтобы избежать дублирования результата во время второго ForEach
в случае, если существуют все три медали.
[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') {
$Bronze = $PSItem -replace ('Silver', 'Bronze')
If ($Collection -contains $Bronze) { "Removing: $Bronze" }
} # If 'Silver'
} # ForEach-Object
$Collection | ForEach-Object -Process {
If ($PSItem -match 'Gold') {
$Silver = $PSItem -replace ('Gold', 'Silver')
$Bronze = $PSItem -replace ('Gold', 'Bronze')
If ($Collection -contains $Silver) { "Removing: $Silver" }
ElseIf ($Collection -contains $Bronze) { "Removing: $Bronze" }
} # If 'Gold'
} # ForEach-Object
Выход:
Removing: Invitational.Bronze.txt
Removing: Olympics.Bronze.txt
Removing: Invitational.Silver.txt