这个自我解答的问题是对this question的后续行动:
如何确定给定数据集的(数组)statistical mode,即最经常出现的一个值或一组值?
例如,在数组1,2,3,4,5
中,有两种模式2
和4
,因为它们是最频繁出现的值。
这个自我解答的问题是对this question的后续行动:
如何确定给定数据集的(数组)statistical mode,即最经常出现的一个值或一组值?
例如,在数组1,2,3,4,5
中,有两种模式2
和4
,因为它们是最频繁出现的值。
结合使用Group-Object
,Sort-Object
和ForEach-Object
:
# Sample dataset.
$dataset = 1,2,3,4,5
do { # dummy loop to allow efficient termination of the pipeline
$dataset | Group-Object | Sort-Object Count -Descending |
ForEach-Object -Begin { $topCount = 0 } -Process {
if ($_.Count -lt $topCount) { break } # No longer top occurrence count,exit
$topCount = $_.Count # Store the occurrence count.
$_.Group[0] # Output the input value represented by the group.
}
} while ($false)
以上产生2
和4
,这是两种模式(值最频繁出现,在这种情况下,每次出现两次);模式按输入顺序返回。
注意:虽然此解决方案从概念上讲是简单明了的,但是可能需要考虑大型数据集的性能。请参见底部,了解对某些输入可能进行的优化。
说明:
Group-Object
按相等性对所有输入进行分组。
Sort-Object -Descending
按成员计数以降序对结果组进行排序(最频繁出现的输入排在最前面)。
ForEach-Object
命令循环遍历已排序的组,并为出现次数(频率)最高的/所有组输出由每个代表的输入。
伪do
循环的原因是,从PowerShell Core 7.0.0-preview.5开始,如果进一步处理,则没有 direct 方式退出管道。不再需要输入。
有一个longstanding feature request on GitHub为此添加支持。
解决方法是使用封闭的循环并使用break
打破它。
注意:在没有封闭循环的管道中,不不要使用break
或continue
,因为它会在封闭循环中查找调用堆栈并退出脚本(如果存在)没有。
通过对比,虽然可以在管道的return
块内使用ForEach-Object
,但它只会跳到 next 输入项-它不会停止处理其他输入。
性能更好的解决方案:
如果输入元素统一为简单数字或字符串(而不是复杂对象),则可以进行优化:
Group-Object
的{{1}}禁止收集每个组中的各个输入。
每个组的-NoElement
属性反映了分组值,但是作为 string 来体现,因此必须将其转换回其原始数据类型。
.Name