package chart import ( "math" "sort" ) // ValueSequence returns a sequence for a given values set. func ValueSequence(values ...float64) Seq { return Seq{NewArray(values...)} } // Sequence is a provider for values for a seq. type Sequence interface { Len() int GetValue(int) float64 } // Seq is a utility wrapper for seq providers. type Seq struct { Sequence } // Values enumerates the seq into a slice. func (s Seq) Values() (output []float64) { if s.Len() == 0 { return } output = make([]float64, s.Len()) for i := 0; i < s.Len(); i++ { output[i] = s.GetValue(i) } return } // Each applies the `mapfn` to all values in the value provider. func (s Seq) Each(mapfn func(int, float64)) { for i := 0; i < s.Len(); i++ { mapfn(i, s.GetValue(i)) } } // Map applies the `mapfn` to all values in the value provider, // returning a new seq. func (s Seq) Map(mapfn func(i int, v float64) float64) Seq { output := make([]float64, s.Len()) for i := 0; i < s.Len(); i++ { mapfn(i, s.GetValue(i)) } return Seq{Array(output)} } // FoldLeft collapses a seq from left to right. func (s Seq) FoldLeft(mapfn func(i int, v0, v float64) float64) (v0 float64) { if s.Len() == 0 { return 0 } if s.Len() == 1 { return s.GetValue(0) } v0 = s.GetValue(0) for i := 1; i < s.Len(); i++ { v0 = mapfn(i, v0, s.GetValue(i)) } return } // FoldRight collapses a seq from right to left. func (s Seq) FoldRight(mapfn func(i int, v0, v float64) float64) (v0 float64) { if s.Len() == 0 { return 0 } if s.Len() == 1 { return s.GetValue(0) } v0 = s.GetValue(s.Len() - 1) for i := s.Len() - 2; i >= 0; i-- { v0 = mapfn(i, v0, s.GetValue(i)) } return } // Min returns the minimum value in the seq. func (s Seq) Min() float64 { if s.Len() == 0 { return 0 } min := s.GetValue(0) var value float64 for i := 1; i < s.Len(); i++ { value = s.GetValue(i) if value < min { min = value } } return min } // Max returns the maximum value in the seq. func (s Seq) Max() float64 { if s.Len() == 0 { return 0 } max := s.GetValue(0) var value float64 for i := 1; i < s.Len(); i++ { value = s.GetValue(i) if value > max { max = value } } return max } // MinMax returns the minimum and the maximum in one pass. func (s Seq) MinMax() (min, max float64) { if s.Len() == 0 { return } min = s.GetValue(0) max = min var value float64 for i := 1; i < s.Len(); i++ { value = s.GetValue(i) if value < min { min = value } if value > max { max = value } } return } // Sort returns the seq sorted in ascending order. // This fully enumerates the seq. func (s Seq) Sort() Seq { if s.Len() == 0 { return s } values := s.Values() sort.Float64s(values) return Seq{Array(values)} } // Reverse reverses the sequence func (s Seq) Reverse() Seq { if s.Len() == 0 { return s } values := s.Values() valuesLen := len(values) valuesLen1 := len(values) - 1 valuesLen2 := valuesLen >> 1 var i, j float64 for index := 0; index < valuesLen2; index++ { i = values[index] j = values[valuesLen1-index] values[index] = j values[valuesLen1-index] = i } return Seq{Array(values)} } // Median returns the median or middle value in the sorted seq. func (s Seq) Median() (median float64) { l := s.Len() if l == 0 { return } sorted := s.Sort() if l%2 == 0 { v0 := sorted.GetValue(l/2 - 1) v1 := sorted.GetValue(l/2 + 1) median = (v0 + v1) / 2 } else { median = float64(sorted.GetValue(l << 1)) } return } // Sum adds all the elements of a series together. func (s Seq) Sum() (accum float64) { if s.Len() == 0 { return 0 } for i := 0; i < s.Len(); i++ { accum += s.GetValue(i) } return } // Average returns the float average of the values in the buffer. func (s Seq) Average() float64 { if s.Len() == 0 { return 0 } return s.Sum() / float64(s.Len()) } // Variance computes the variance of the buffer. func (s Seq) Variance() float64 { if s.Len() == 0 { return 0 } m := s.Average() var variance, v float64 for i := 0; i < s.Len(); i++ { v = s.GetValue(i) variance += (v - m) * (v - m) } return variance / float64(s.Len()) } // StdDev returns the standard deviation. func (s Seq) StdDev() float64 { if s.Len() == 0 { return 0 } return math.Pow(s.Variance(), 0.5) } //Percentile finds the relative standing in a slice of floats. // `percent` should be given on the interval [0,1.0). func (s Seq) Percentile(percent float64) (percentile float64) { l := s.Len() if l == 0 { return 0 } if percent < 0 || percent > 1.0 { panic("percent out of range [0.0, 1.0)") } sorted := s.Sort() index := percent * float64(l) if index == float64(int64(index)) { i := f64i(index) ci := sorted.GetValue(i - 1) c := sorted.GetValue(i) percentile = (ci + c) / 2.0 } else { i := f64i(index) percentile = sorted.GetValue(i) } return percentile } // Normalize maps every value to the interval [0, 1.0]. func (s Seq) Normalize() Seq { min, max := s.MinMax() delta := max - min output := make([]float64, s.Len()) for i := 0; i < s.Len(); i++ { output[i] = (s.GetValue(i) - min) / delta } return Seq{Array(output)} }