如何在PowerShell中编辑hashtable列表并实现去重与最优项筛选?
PowerShell哈希表列表编辑优化方案
我正在寻找PowerShell中编辑哈希表列表的更优方法,目前已能遍历列表检测重复项,但不确定如何编辑哈希表并更新列表,且希望能支持大规模操作。
测试数据
测试数据格式如下(实际环境就是这种格式):
$TEST_DATA = @( "CA>TORONTO>MAP-LAYOUT-1", ` "US>NEW-YORK>MAP-LAYOUT-25", ` "US>DENVER>MAP-LAYOUT-2", ` "UK>LODNON>MAP-LAYOUT-2", ` "EU>PARIS>MAP-LAYOUT-25", ` "EU>VENICE>MAP-LAYOUT-2", ` "EU>BERLIN>MAP-LAYOUT-8", ` "EU>PARIS>MAP-LAYOUT-30", ` "EU>VENICE>NEW-MAP-LAYOUT-2", ` "EU>ATHENS>NEW-MAP-LAYOUT-8", ` "CA>TORONTO>NEW-MAP-LAYOUT-1", ` "CA>VANCOUVER>MAP-LAYOUT-1", ` "US>MIAMI>MAP-LAYOUT-25", ` "RU>MOSCOW>MAP-LAYOUT-2", ` "RU>ST-PETERSBURG>MAP-LAYOUT-2", ` "JP>TOKYO>MAP-LAYOUT-25", ` "EU>PARIS>MAP-LAYOUT-100", ` "AU>SYDNEY>MAP-LAYOUT-3", ` "AU>PERTH>MAP-LAYOUT-3", ` "MX>MEXICO-CITY>MAP-LAYOUT-5", ` "MX>TIJAUNA>MAP-LAYOUT-1", ` "CN>SHANGHAI>MAP-LAYOUT-8", ` "CA>CALGARY>MAP-LAYOUT-1" )
当前脚本
我目前的PowerShell脚本如下:
$MAPS = @() $TEST_DATA | Foreach { $COUNTRY = ($_).split('>')[0] $CITY = ($_).split('>')[1] $MAP = ($_).split('>')[2] If ( $MAPS.count -gt 0) { $MAPS | Foreach { $MAPS_ROW = $_ Write-Host $MAPS_ROW If (( $MAPS_ROW.COUNTRY -eq $COUNTRY ) -and ( $MAPS_ROW.CITY -eq $CITY )) { Write-Host '--------' -ForegroundColor Red Write-Host "CONFLICT DETECTED ! " write-Host '--------' -ForegroundColor Red Write-Host "" Write-Host "CONFLICT MAP : $MAPS_ROW" Write-Host "" If (($MAP.lenght -gt $MAPS_ROW.MAP.length) -or ( $MAP.lenght -gt ($MAPS_ROW.MAP.trim("NEW-")).length)) { $MAPS.Remove($MAPS_ROW) $NEW_MAP = New-Object PSObject -property @{ COUNTRY="$COUNTRY"; CITY="$CITY"; MAP="$MAP"; } $MAPS += $NEW_MAP } else { Write-Host '--------' -ForegroundColor Yellow Write-Host "FALSE MAP CONFLICT DETECHED ! $MAPS_ROW " Write-Host '--------' -ForegroundColor Yellow } } else { Write-Host '--------' -ForegroundColor BLue Write-Host "NOT IN : 'MAPS'" Write-Host '--------' -ForegroundColor Blue } } $NEW_MAP = New-Object PSObject -property @{ COUNTRY="$COUNTRY"; CITY="$CITY"; MAP="$MAP"; } $MAPS += $NEW_MAP } else { Write-Host '--------' -ForegroundColor BLue Write-Host "First MAP Entry" Write-Host '--------' -ForegroundColor Blue $NEW_MAP = New-Object PSObject -property @{ COUNTRY="$COUNTRY"; CITY="$CITY"; MAP="$MAP"; } $MAPS += $NEW_MAP } } $SORTED_MAPS = $MAPS | Sort-Object { $_.COUNTRY }, { $_.CITY }, { $_.MAP } | Select-Object @{n="COUNTRY";e={$_.COUNTRY}}, @{n="CITY";e={$_.CITY}}, @{n="MAP";e={$_.MAP}} Write-Host '--------' -ForegroundColor Blue $SORTED_MAPS Write-Host '--------' -ForegroundColor Blue
当前输出结果
当前脚本运行后生成的排序列表:
COUNTRY CITY MAP ------- ---- --- AU PERTH MAP-LAYOUT-3 AU SYDNEY MAP-LAYOUT-3 CA CALGARY MAP-LAYOUT-1 CA TORONTO MAP-LAYOUT-1 CA TORONTO NEW-MAP-LAYOUT-1 CA VANCOUVER MAP-LAYOUT-1 CN SHANGHAI MAP-LAYOUT-8 EU ATHENS NEW-MAP-LAYOUT-8 EU BERLIN MAP-LAYOUT-8 EU PARIS MAP-LAYOUT-100 EU PARIS MAP-LAYOUT-25 EU PARIS MAP-LAYOUT-30 EU VENICE MAP-LAYOUT-2 EU VENICE NEW-MAP-LAYOUT-2 JP TOKYO MAP-LAYOUT-25 MX MEXICO-CITY MAP-LAYOUT-5 MX TIJAUNA MAP-LAYOUT-1 RU MOSCOW MAP-LAYOUT-2 RU ST-PETERSBURG MAP-LAYOUT-2 UK LODNON MAP-LAYOUT-2 US DENVER MAP-LAYOUT-2 US MIAMI MAP-LAYOUT-25 US NEW-YORK MAP-LAYOUT-25
存在的问题
- 如何从列表中移除重复项?尝试过
Sort-Object -Unique但未成功。 - 如何确保每个城市仅保留一个条目,且对应最优的MAP名称?筛选规则:含"NEW-"标签的MAP优先级最高;其次选择编号最大的MAP(如巴黎应保留MAP-LAYOUT-100)。曾尝试检查Country和City字段,但无法顺利对数组中的哈希表进行增删操作。
- 是否创建新的ArrayList来处理MAP排序会更合适?
解决方案
1. 高效去重并筛选最优MAP条目
不用手动遍历检测冲突,直接用Group-Object按Country和City分组,然后对每组内的条目按规则排序,取最优的那个。这种方法代码更简洁,效率更高,适合大规模数据:
# 处理测试数据,转换为自定义对象并提取排序关键字 $processedData = $TEST_DATA | ForEach-Object { $parts = $_ -split '>' [PSCustomObject]@{ Country = $parts[0] City = $parts[1] Map = $parts[2] IsNew = $parts[2] -match '^NEW-' # 标记是否为NEW-开头的MAP MapNum = [int]($parts[2] -split '-')[-1] # 提取MAP的编号数字 } } # 按Country+City分组,每组内按优先级排序(NEW-优先,编号降序),取第一个最优条目 $finalMaps = $processedData | Group-Object Country,City | ForEach-Object { $_.Group | Sort-Object -Property IsNew -Descending, MapNum -Descending | Select-Object -First 1 -Property Country,City,Map } # 最终排序输出 $finalMaps | Sort-Object Country,City | Format-Table -AutoSize
运行后输出会自动每个城市只保留最优条目:
Country City Map ------- ---- --- AU PERTH MAP-LAYOUT-3 AU SYDNEY MAP-LAYOUT-3 CA CALGARY MAP-LAYOUT-1 CA TORONTO NEW-MAP-LAYOUT-1 CA VANCOUVER MAP-LAYOUT-1 CN SHANGHAI MAP-LAYOUT-8 EU ATHENS NEW-MAP-LAYOUT-8 EU BERLIN MAP-LAYOUT-8 EU PARIS MAP-LAYOUT-100 EU VENICE NEW-MAP-LAYOUT-2 JP TOKYO MAP-LAYOUT-25 MX MEXICO-CITY MAP-LAYOUT-5 MX TIJAUNA MAP-LAYOUT-1 RU MOSCOW MAP-LAYOUT-2 RU ST-PETERSBURG MAP-LAYOUT-2 UK LODNON MAP-LAYOUT-2 US DENVER MAP-LAYOUT-2 US MIAMI MAP-LAYOUT-25 US NEW-YORK MAP-LAYOUT-25
2. 关于ArrayList的使用
如果处理十万级以上的大规模数据,用ArrayList比普通数组更高效。因为普通数组是固定大小的,每次+=操作都会创建新数组并复制原有数据,数据量越大越慢。而ArrayList支持动态添加/删除元素,操作效率更高。
示例用法:
# 创建ArrayList实例 $mapList = New-Object System.Collections.ArrayList $TEST_DATA | ForEach-Object { $parts = $_ -split '>' $entry = [PSCustomObject]@{ Country = $parts[0] City = $parts[1] Map = $parts[2] } # 添加元素到ArrayList,[void]用于屏蔽Add方法返回的索引值 [void]$mapList.Add($entry) } # 示例:移除第一个元素 $mapList.RemoveAt(0)
但对于你的需求,用前面的Group-Object+Sort-Object方法已经足够高效,不需要手动用ArrayList处理增删,除非你有更复杂的实时编辑需求。
3. 为什么Sort-Object -Unique没生效
Sort-Object -Unique是根据排序后的整个对象或指定属性去重,你之前的排序是按Country、City、Map,同一Country+City下的Map值不同,所以不会被去重。要实现按Country+City去重并保留最优项,必须先分组再筛选,而不是直接用-Unique参数。
内容的提问来源于stack exchange,提问作者Mr. E
相关产品推荐
相关产品推荐

