使用排序从切片的间隔中获取最大值和最小值



我在操场上有这个代码。我正在使用排序从切片/数组中获取最大和最小值。当我需要得到x周期内的值时问题就开始了。如果你运行这段代码,你会在最后一次打印中得到1.0407的值,但是在x周期之前不再有这个值,这个值离x的周期很远。我的问题是,他为什么要偷看这个值?而min没有。

package main
import (
"fmt"
"math"
"sort"
)
func main() {
var x = []float64{1.0073, 1.0129, 1.014, 1.017, 1.0173, 1.0171, 1.0171, 1.0174, 1.0154, 1.0142, 1.0116, 1.0116, 1.0118, 1.0084, 1.0087, 1.0086, 1.0077, 1.0154, 1.0155, 1.0207, 1.0218, 1.0273, 1.0257, 1.0244, 1.0243, 1.0237, 1.026, 1.0251, 1.0239, 1.025, 1.0246, 1.0245, 1.0234, 1.024, 1.0247, 1.0229, 1.0274, 1.0326, 1.0319, 1.0314, 1.0331, 1.0301, 1.0311, 1.0307, 1.028, 1.0298, 1.0305, 1.0296, 1.0293, 1.0296, 1.0291, 1.0288, 1.029, 1.029, 1.0313, 1.0315, 1.0318, 1.0366, 1.0387, 1.0363, 1.0366, 1.0353, 1.036, 1.0364, 1.0369, 1.0341, 1.0326, 1.0345, 1.033, 1.0316, 1.0324, 1.032, 1.0325, 1.032, 1.0325, 1.0317, 1.0317, 1.0324, 1.0335, 1.036, 1.0368, 1.034, 1.0347, 1.035, 1.0354, 1.039, 1.0407, 1.0374, 1.0362, 1.0349, 1.0326, 1.0285, 1.0298, 1.0301, 1.0318, 1.0326, 1.0329, 1.032, 1.0303, 1.0305, 1.0305, 1.0311, 1.0303, 1.0303, 1.0295, 1.0304, 1.031, 1.0305, 1.0305, 1.0288, 1.0287, 1.029, 1.0289, 1.0293, 1.0299, 1.0297, 1.0286, 1.028, 1.0292, 1.0292, 1.0286, 1.0295, 1.0282, 1.0291, 1.029, 1.0292, 1.0287, 1.0294, 1.0274, 1.0267, 1.0266, 1.0249, 1.0245, 1.0226, 1.0221, 1.0237, 1.0243, 1.0264, 1.025, 1.0263, 1.0268, 1.0256, 1.0263, 1.0257, 1.0253, 1.0246, 1.0257, 1.0263, 1.0258, 1.026, 1.0264, 1.0266, 1.0295, 1.0283, 1.0309, 1.0296, 1.0299, 1.0294, 1.0287, 1.0277, 1.0285, 1.03, 1.0323, 1.032, 1.0315, 1.0325, 1.0336, 1.0336, 1.0337, 1.0337, 1.0326, 1.0328, 1.0329, 1.0335, 1.0327, 1.0347, 1.0331, 1.0359, 1.0357, 1.0332, 1.0328, 1.0308, 1.0307, 1.0304, 1.0303, 1.0271, 1.0284, 1.0293, 1.0308, 1.0312, 1.0309, 1.0311, 1.0309, 1.0305, 1.0314, 1.0306, 1.0302, 1.0299, 1.0294, 1.0286, 1.0292, 1.0288, 1.0295, 1.0301, 1.0304, 1.0286, 1.0275, 1.0265, 1.0262, 1.0271, 1.027, 1.0263, 1.026, 1.0258, 1.0257, 1.0257, 1.0261, 1.0264, 1.0242, 1.0256, 1.0265, 1.0263, 1.0258, 1.0264, 1.0253, 1.0243, 1.0239, 1.0243, 1.0258, 1.0234, 1.0227, 1.0181, 1.0189, 1.0117, 1.0128, 1.0143, 1.0154, 1.0154, 1.0144, 1.0122, 1.0129, 1.0123, 1.0128, 1.0133, 1.0136, 1.0134, 1.0134, 1.0142, 1.0132, 1.0127, 1.0113, 1.0122, 1.0119, 1.0105, 1.0108, 1.0079, 1.0082, 1.0082, 1.0091, 1.0105, 1.0121, 1.0122, 1.0115, 1.0123, 1.0118, 1.0123, 1.0111, 1.0106, 1.0099, 1.01, 1.0107, 1.0111, 1.0103, 1.0128, 1.0115, 1.0109, 1.0081, 1.0083, 1.0096, 1.0089, 1.0097, 1.0106, 1.0121, 1.0124, 1.0136, 1.0118, 1.0134, 1.0137, 1.0152, 1.0147, 1.0141, 1.0144, 1.0139, 1.0145, 1.0146, 1.0156, 1.0145, 1.014, 1.014, 1.0124}
var period = 5
var highest float64
var lowest float64
for i, v := range x {
if i < period {
continue
}
var correctHighest, correctLowest = MaxMin(x[i-period : i])
fmt.Println("Correct -", "Price:", v, "Highest:", correctHighest, "Lowest:", correctLowest)
}
for i, v := range x {
if i < period {
continue
}
var correctHighest, correctLowest = MaxMin(x[i-period : i])
fmt.Println("Correct -", "Highest:", correctHighest, "Lowest:", correctLowest)
highest = Max(x[i-period : i]...)
lowest = Min(x[i-period : i]...)
fmt.Println("Price:", v, "Highest:", highest, "Lowest:", lowest)
}
}
// Both does not work
func Max(n ...float64) float64 {
sort.Float64s(n)
if len(n) == 0 {
return 0.
}
return n[len(n)-1]
}
func Min(n ...float64) float64 {
sort.Float64s(n)
if len(n) == 0 {
return 0.
}
return n[0]
}
// New code that works
func MaxMin(n []float64) (float64, float64) {
if len(n) == 0 {
return 0., 0.
}
var max float64
var min = math.MaxFloat64
for _, value := range n {
if value > max {
max = value
}
if value < min {
min = value
}
}
return max, min
}

实际情况是,切片是对后备数组的引用,sort对切片进行排序。这意味着排序调用。Float64s实际上是在修改(排序)x片的内容(更准确地说,是x的子片的内容,但后台数组是相同的)。

正如我在上面的评论中提到的,使用排序只是为了找到最小/最大值并不是一个好主意,因为它将比扫描最小/最大值的简单循环慢。但是如果你真的想使用它,你需要在将这些切片传递给sort.Float64s之前对它们进行深度拷贝。


关于上面代码的小注意事项:如果所有元素都是负的,或者它们都是NaN,则MaxMin函数不是真正正确的。您可能想要这样做:https://godbolt.org/z/E5e5q7ePa(未测试)。

func MinMax(n []float64) (min float64, max float64) {
min, max = math.NaN(), math.NaN()
for _, e := range n {
if e < min || (math.IsNaN(min) && !math.IsNaN(e)) {
min = e
}
if e > max || (math.IsNaN(max) && !math.IsNaN(e)) {
max = e
}
}
return
}

最新更新