我想要实现一个简单的目标。在多台服务器上按定义的顺序停止一些服务,然后按相反的顺序启动它们。
因此,第一步是定义一个有序的哈希表/字典。
$serviceServer = [ordered]@{
"service3" = @("server1")
"service1" = @("server2", "server3")
"service2" = @("server1", "server2", "server3")
}
但是我如何逆转服务重新启动的顺序呢?
在 php 中我会做一个 array_reverse …没什么大不了的,但 Powershell 似乎有它自己的简单含义。
我尝试了多种方式对 Sort-Object 进行排序,但顺序保持不变。
$reverseServices = $serviceServer | Sort-Object
看看这个并自己尝试一下,我已经做了一些性能测试。
$serviceServers = [ordered]@{
"service3" = @("server1")
"service1" = @("server2", "server3")
"service2" = @("server1", "server2", "server3")
"service6" = @("server1")
"service4" = @("server2", "server3")
"service5" = @("server1", "server2", "server3")
"service9" = @("server1")
"service7" = @("server2", "server3")
"service8" = @("server1", "server2", "server3")
}
function Reverse-ByEnum1 {
param(
$serviceServer
)
$keys = @($serviceServer.Keys)
$serviceServer.GetEnumerator() | Sort-Object { $keys.IndexOf($_.Key) } -Descending
}
function Reverse-ByEnum2 {
param(
$serviceServer
)
$serviceServer.GetEnumerator() `
| foreach-object `
-begin { $r = [ordered] @{} } `
-process { $r.Insert(0, $_.Key, $_.Value) } `
-end { $r }
}
function Reverse-ByKeys {
param(
$serviceServer
)
$reversedServiceServer = [ordered] @{}
foreach ($key in $serviceServer.Keys) {
$reversedServiceServer.Insert(0, $key, $serviceServer[$key])
}
$reversedServiceServer
}
Measure-Command {
for ($i = 0; $i -lt 10000; $i++) {
$reverse1 = Reverse-ByEnum1 $serviceServers
}
}
Measure-Command {
for ($i = 0; $i -lt 10000; $i++) {
$reverse2 = Reverse-ByEnum2 $serviceServers
}
}
Measure-Command {
for ($i = 0; $i -lt 10000; $i++) {
$reverse3 = Reverse-ByKeys $serviceServers
}
}
Write-Host =====================================================================
$reverse1
Write-Host =====================================================================
$reverse2
Write-Host =====================================================================
$reverse3
6
最佳答案
3
要构造一个以相反顺序包含原始哈希表条目的新有序哈希表,您可以枚举原始字典中的键并将位置处的每个新条目插入到新字典中,这实际上会反转原始顺序 – 这是的非管道替代方案,借鉴了该巧妙的技巧:0
# Construct a new ordered hashtable with the entries of the original one in
# reverse order.
$reversedServiceServer = [ordered] @{}
foreach ($key in $serviceServer.Keys) {
$reversedServiceServer.Insert(0, $key, $serviceServer[$key])
}
$reversedServiceServer # Print the new hashtable, for visual verification.
如果以相反的顺序流式传输有序字典的条目就足够了,使用管道:
$i = 0; $serviceServer.GetEnumerator() | Sort-Object { (--([ref] $i).Value) }
更新:中的基于 的解决方案是一种更高效、更优雅的替代方法(它以相反的顺序返回原始字典条目的堆栈;如果在管道中使用,条目将被自动枚举;要明确将堆栈变成数组,请附加)。.ToArray()
-
虽然比顶部的解决方案更简洁,但由于通常使用管道,
Sort-Object
特别是使用计算属性(脚本块),它显然更慢(尽管对于小的哈希表来说这并不重要)。 -
该
Sort-Object
调用使用辅助变量,该变量针对每个输入对象减少,因此实际上反转了输入对象的顺序;[1] 是在父([ref] $i)
范围中引用变量的简洁方式,这是必要的,因为子范围中运行。$i
-
虽然输出看起来像一个条目反转的有序哈希表,但它是一个实例流,每个实例都有一个
.Key
和一个.Value
属性(PowerShell 另外将其别名.Key
为.Name
)。
[1] 这项技术是从中借鉴而来的。
1
-
1这似乎是实际上最快和最好理解的方式。
–
|
三个想法,一个是使用IndexOf
和-Descending
排序:
$serviceServer = [ordered]@{
'service3' = @('server1')
'service1' = @('server2', 'server3')
'service2' = @('server1', 'server2', 'server3')
'servicefoo' = @('server1')
}
$keys = @($serviceServer.Keys)
$serviceServer.GetEnumerator() | Sort-Object { $keys.IndexOf($_.Key) } -Descending
第二个是使用:
[System.Linq.Enumerable]::Reverse([object[]] $serviceServer.Keys) |
ForEach-Object { "Service: '$_' - [$($serviceServer[$_])]" }
第三个是通过强制转换为:
[System.Collections.Stack] $serviceServer
在所有情况下,原件OrderedDictionary
都是完整的,但您可以按照此逻辑创建一个新的。
3
-
1看上去很高效。
– -
1@elh 不认为效率对于这么小的字典那么重要,我添加了第三个选项,在我看来,最简单的一个是使用
Stack
– -
1@mklement0 谢谢。我没想到这会有用,但确实有用,太棒了!
–
|
另一个选项是返回反转的OrderedDictionary
,以防万一有要求的话:
$reversed = $serviceServer.GetEnumerator() `
| foreach-object `
-begin { $r = [ordered] @{} } `
-process { $r.Insert(0, $_.Key, $_.Value) } `
-end { $r }
它使用 OrderedDictionaryInsert
方法遍历原始集合并将每个项目插入新实例的开头,从而有效地将其反转。
1
-
1哦天哪…它变得越来越高效了。
–
|
–
–
–
–
–
|