github.com/diadata-org/diadata@v1.4.593/pkg/utils/slices.go (about) 1 package utils 2 3 import ( 4 "math" 5 "sort" 6 "time" 7 ) 8 9 // ArgsortableSlice is a wrapper struct around the sort interface. It allows 10 // for implemetation of argsort for all sortable types. 11 type ArgsortableSlice struct { 12 sort.Interface 13 idx []int 14 } 15 16 type TimeBin struct { 17 Starttime time.Time 18 Endtime time.Time 19 } 20 21 func (as ArgsortableSlice) Ind() []int { 22 return as.idx 23 } 24 25 // Swap swaps the corresponding indices together with the values. 26 func (s ArgsortableSlice) Swap(i, j int) { 27 s.Interface.Swap(i, j) 28 s.idx[i], s.idx[j] = s.idx[j], s.idx[i] 29 } 30 31 // NewFloat64Slice returns the wrapped float64slice that can be argsorted. 32 func NewFloat64Slice(sf sort.Float64Slice) *ArgsortableSlice { 33 s := &ArgsortableSlice{ 34 Interface: sf, 35 idx: make([]int, sf.Len()), 36 } 37 for i := range s.idx { 38 s.idx[i] = i 39 } 40 return s 41 } 42 43 // TO DO: Switch to generics for these simple algebraic functions. 44 45 // Average returns the average of @samples. 46 func Average(series []float64) (average float64) { 47 length := float64(len(series)) 48 if length == 0 { 49 return 50 } 51 for _, s := range series { 52 average += s 53 54 } 55 average /= length 56 return 57 } 58 59 func Variance(series []float64) (variance float64) { 60 length := float64(len(series)) 61 if length == 0 { 62 return 63 } 64 if length == 1 { 65 return 0 66 } 67 68 avg := Average(series) 69 for _, item := range series { 70 variance += math.Pow(item-avg, float64(2)) 71 } 72 variance /= (length - 1) 73 return 74 } 75 76 func StandardDeviation(series []float64) float64 { 77 return math.Sqrt(Variance(series)) 78 } 79 80 // MakeBins returns a slice of @TimeBin according to block sizes and time shifts. 81 func MakeBins(starttime time.Time, endtime time.Time, blockSizeSeconds int64, blockShiftSeconds int64) (bins []TimeBin) { 82 timeInit := starttime 83 blockDuration := time.Duration(blockSizeSeconds) * time.Second 84 85 for timeInit.Add(blockDuration).Before(endtime) || timeInit.Add(blockDuration) == endtime { 86 b := TimeBin{Starttime: timeInit, Endtime: timeInit.Add(time.Duration(blockSizeSeconds) * time.Second)} 87 bins = append(bins, b) 88 timeInit = timeInit.Add(time.Duration(blockShiftSeconds) * time.Second) 89 } 90 91 return 92 } 93 94 // IsInBin returns true in case @timestamp is in half-open interval @bin. 95 func IsInBin(timestamp time.Time, bin TimeBin) bool { 96 if timestamp.After(bin.Starttime) && timestamp.Before(bin.Endtime) { 97 return true 98 } 99 if timestamp == bin.Endtime { 100 return true 101 } 102 return false 103 }