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  }