使用Go在片段结构中按时间平均
I'm averaging values by hour in a slice of structs in a basic way, and I would get a better aproach to it in order to get a most generic funcion that can get averaging by hours, days, weeks, etc. Thanks in advance to everybody.
package main
import (
"fmt"
"math/rand"
"time"
)
type Acc struct {
name string
money int
date time.Time
}
type Accs []Acc
const Tformat = "02/01/2006 15:04:05"
func main() {
var myaccs Accs
acc := 0
var loops int
var hour int
f1, _ := time.Parse(Tformat, "29/08/2013 00:00:19")
// Creating a Slice of structs
for i := 0; i < 10; i++ {
f1 = f1.Add(20 * time.Minute) //adding 20 minutes to every record
myaccs = append(myaccs, Acc{name: "christian", money: rand.Intn(200), date: f1})
fmt.Printf("Added to slice: %v, %d, %s
", myaccs[i].name, myaccs[i].money, myaccs[i].date)
}
// Averaging
for _, v := range myaccs {
if acc == 0 {
hour = v.date.Hour()
acc += v.money
loops++
} else {
if v.date.Hour() == hour {
acc += v.money
loops++
} else {
fmt.Printf("Average money value to hour %d : %d
", hour, acc / loops) //->Action
acc = v.money
hour = v.date.Hour()
loops = 1
}
}
//fmt.Println(v, acc, loops, hour)
}
fmt.Printf("Average money value to hour %d : %d
", hour, acc / loops)//->Action
}
Note: Money variable is a int like a example only..
Note2: I'm considering that the data are already sorted
Playground:
http://play.golang.org/p/lL3YDD4ecE
Time math is frought with peril, but here is one way to approach the problem:
type Snapshot struct {
Value AccountValue
At time.Time
}
type Granularity struct {
Name string
DateIncrement [3]int
DurIncrement time.Duration
DateFormat string
}
type Graph struct {
Granularity
Values map[string][]AccountValue
}
func (g *Graph) Add(snaps []Snapshot) {
if g.Values == nil {
g.Values = map[string][]AccountValue{}
}
for _, s := range snaps {
key := g.Format(s.At)
g.Values[key] = append(g.Values[key], s.Value)
}
}
func (g *Graph) Get(from, to time.Time) (snaps []Snapshot) {
from, to = g.Truncate(from), g.Truncate(to)
for cur := from; !to.Before(cur); cur = g.AddTo(cur) {
var avg, denom AccountValue
for _, v := range g.Values[g.Format(cur)] {
avg += v
denom += 1
}
if denom > 0 {
avg /= denom
}
snaps = append(snaps, Snapshot{
Value: avg,
At: cur,
})
}
return snaps
}
Full code in Playground
For unsorted data
Start by implementing the sort interface on the type Accs []Acc. Then you can easily sort by hours, days, weeks.
For sorted data
Create a GroupBy method on Accs.
func (accs Accs) GroupBy(p func(Acc,Acc) bool) [][]Accs {
// your looping/comparing/grouping code goes here
}
Use the predicate function p to pass in group specific code for comparing two Acc structs to see if they should go in the same group.
Once the Accs are in groups you can sum, avg etc.