在Go语言中,对结构体切片按时间进行平均的方法是什么?

huangapple go评论158阅读模式
英文:

Averaging by time in a slice of structs with Go

问题

我正在以一种基本的方式按小时对结构体切片中的值进行平均,我想得到一种更通用的方法,可以按小时、天、周等进行平均。提前感谢大家。

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")
	// 创建一个结构体切片
	for i := 0; i < 10; i++ {
		f1 = f1.Add(20 * time.Minute) // 每个记录增加20分钟
		myaccs = append(myaccs, Acc{name: "christian", money: rand.Intn(200), date: f1})
		fmt.Printf("添加到切片中:%v, %d, %s\n", myaccs[i].name, myaccs[i].money, myaccs[i].date)
	}
	// 平均值计算
	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("小时 %d 的平均金额:%d\n", hour, acc/loops) //->Action

				acc = v.money
				hour = v.date.Hour()
				loops = 1
			}
		}
		//fmt.Println(v, acc, loops, hour)
	}
	fmt.Printf("小时 %d 的平均金额:%d\n", hour, acc/loops) //->Action
}

注意:Money变量只是一个示例,是一个整数。
注意2:我假设数据已经排序好了。

Playground:
http://play.golang.org/p/lL3YDD4ecE

英文:

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 (
&quot;fmt&quot;
&quot;math/rand&quot;
&quot;time&quot;
)
type Acc struct {
name  string
money int
date time.Time
}
type Accs []Acc
const Tformat = &quot;02/01/2006 15:04:05&quot;
func main() {
var myaccs Accs
acc := 0
var loops int
var hour int
f1, _ := time.Parse(Tformat, &quot;29/08/2013 00:00:19&quot;)
// Creating a Slice of structs 
for i := 0; i &lt; 10; i++ { 
f1 = f1.Add(20 * time.Minute) //adding 20 minutes to every record
myaccs = append(myaccs, Acc{name: &quot;christian&quot;, money: rand.Intn(200), date: f1})
fmt.Printf(&quot;Added to slice: %v, %d, %s\n&quot;, 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(&quot;Average money value to hour %d : %d\n&quot;, hour, acc / loops) //-&gt;Action
acc = v.money
hour = v.date.Hour()
loops = 1
}
}
//fmt.Println(v, acc, loops, hour)
}
fmt.Printf(&quot;Average money value to hour %d : %d\n&quot;, hour, acc / loops)//-&gt;Action
}

Note: Money variable is a int like a example only..<br>
Note2: I'm considering that the data are already sorted<br>
Playground:
http://play.golang.org/p/lL3YDD4ecE

答案1

得分: 2

时间数学问题充满了风险,但是这里是一种解决该问题的方法:

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
}

完整代码请参见Playground

英文:

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 &gt; 0 {
avg /= denom
}
snaps = append(snaps, Snapshot{
Value: avg,
At:    cur,
})
}
return snaps
}

Full code in Playground

答案2

得分: 1

对于未排序的数据

首先,在类型 Accs []Acc 上实现排序接口。然后,你可以根据小时、天、周等进行排序。

对于已排序的数据

在 Accs 上创建一个 GroupBy 方法。

func (accs Accs) GroupBy(p func(Acc,Acc) bool) [][]Accs {
// 在这里编写循环/比较/分组代码
}

使用谓词函数 p 来传递特定于分组的代码,以比较两个 Acc 结构,看它们是否应该放在同一组中。

一旦 Accs 被分组,你就可以进行求和、平均值等操作。

英文:

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.

huangapple
  • 本文由 发表于 2013年9月2日 22:20:50
  • 转载请务必保留本文链接:https://go.coder-hub.com/18575358.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定