how to group by multiple value and sum multiple value in golang

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

how to group by multiple value and sum multiple value in golang

问题

我有这段代码:

type key struct {
	account  string
	quantity float64
}
type invoice_tag struct {
	account              string
	value_after_discount float64
	value                float64
	price                float64
	total_discount       float64
	discount             float64
	quantity             float64
}

invoice := []invoice_tag{{"Cash", 1024, 1024, 1, 0, 0, 1024}, {"Service Revenue", 0, 2048, 2, 0, 0, 1024}, {"Service Revenue", 0, 0, 0, 1024, 1, 1024}}
m := map[key][5]float64{}
for _, i := range invoice {
	m[key{i.account, i.quantity}] = [5]float64{i.value_after_discount, i.value, i.price, i.total_discount, i.discount}

}
fmt.Println(m)

我想按accountquantity进行分组,并将value_after_discountvalue_after_discount相加,将valuevalue相加,将priceprice相加,将total_discounttotal_discount相加,将discountdiscount相加。输出应为:

map[{Cash 1024}:[1024 1024 1 0 0] {Service Revenue 1024}:[1024 2048 2 1024 1]]

你可以在这里查看代码:链接

英文:

i have this code

	type key struct {
		account  string
		quantity float64
	}
	type invoice_tag struct {
		account              string
		value_after_discount float64
		value                float64
		price                float64
		total_discount       float64
		discount             float64
		quantity             float64
	}

	invoice := []invoice_tag{{"Cash", 1024, 1024, 1, 0, 0, 1024}, {"Service Revenue", 0, 2048, 2, 0, 0, 1024}, {"Service Revenue", 0, 0, 0, 1024, 1, 1024}}
	m := map[key][5]float64{}
	for _, i := range invoice {
		m[key{i.account, i.quantity}] = [5]float64{i.value_after_discount, i.value, i.price, i.total_discount, i.discount}

	}
	fmt.Println(m)

i want to group by account and quantity and to sum value_after_discount with value_after_discount and value with value and price with price and total_discount with total_discount and discount with discount. and the output should be

map[{Cash 1024}:[1024 1024 1 0 0] {Service Revenue 1024}:[1024 2048 2 1024 1]]

https://play.golang.org/p/KKTmovpfN1z

答案1

得分: 0

使用一个结构体作为复合键,其中包含accountquantity字段。注意:浮点数比较可能会让你感到惊讶,如果quantity是整数,你应该使用整数(例如int)!

使用一个结构体来保存你想要求和的值。为了简单起见,我将使用invoice_tag,因为它包含了所有必需的字段,但你也可以根据自己的喜好创建一个单独的结构体。

我将在映射中存储对这个结构体的指针,这样在每次迭代中更新它时,我就不必存储新值。

例如:

m := map[key]*invoice_tag{}
for _, i := range invoice {
    k := key{i.account, i.quantity}
    sums := m[k]
    if sums == nil {
        sums = &invoice_tag{}
        m[k] = sums
    }
    sums.value_after_discount += i.value_after_discount
    sums.value += i.value
    sums.price += i.price
    sums.total_discount += i.total_discount
    sums.discount += i.discount
}

for k, v := range m {
    fmt.Printf("key: %v, sums: value_after_discount: %f, value: %f, price: %f, total_discount: %f, discount: %f\n",
        k, v.value_after_discount, v.value, v.price, v.total_discount, v.discount)
}

这将输出(在Go Playground上尝试):

key: {Cash 1024}, sums: value_after_discount: 1024.000000, value: 1024.000000, price: 1.000000, total_discount: 0.000000, discount: 0.000000
key: {Service Revenue 1024}, sums: value_after_discount: 0.000000, value: 2048.000000, price: 2.000000, total_discount: 1024.000000, discount: 1.000000

再次强调:这个方法之所以有效,是因为我们使用的输入数据包含相同的浮点数常量字面值(这导致了相同的float64值)。在实际应用中,由于IEEE 754浮点数的怪异之处,分组可能会给出错误的结果。如果可能的话,我建议对数量使用int。如果不可能,请将数量格式化为相同的格式(包括某些位数的四舍五入)。

英文:

Use a struct as the composite key with account and quantity fields. Note: float number comparisons may surprise you, if quantity is an integer number, you should use an integer number (e.g. int)!

Use a struct that holds the values you want to sum. For simplicity, I'll use invoice_tag for this because it contains all the required fields, but you may create a separate struct too to your liking.

I'll store a pointer to this struct in the map, so when I update it in each iteration, I don't have to store the new value.

For example:

m := map[key]*invoice_tag{}
for _, i := range invoice {
	k := key{i.account, i.quantity}
	sums := m[k]
	if sums == nil {
		sums = &invoice_tag{}
		m[k] = sums
	}
	sums.value_after_discount += i.value_after_discount
	sums.value += i.value
	sums.price += i.price
	sums.total_discount += i.total_discount
	sums.discount += i.discount
}

for k, v := range m {
	fmt.Printf("key: %v, sums: value_after_discount: %f, value: %f, price: %f, total_discount: %f, discount: %f\n",
		k, v.value_after_discount, v.value, v.price, v.total_discount, v.discount)
}

This will output (try it on the Go Playground):

key: {Cash 1024}, sums: value_after_discount: 1024.000000, value: 1024.000000, price: 1.000000, total_discount: 0.000000, discount: 0.000000
key: {Service Revenue 1024}, sums: value_after_discount: 0.000000, value: 2048.000000, price: 2.000000, total_discount: 1024.000000, discount: 1.000000

Again: this works because the input data we used contains identical floating point constant literals (which result in identical float64 value). In practice the grouping may give incorrect results due to IEEE 754 floating point quirks. I recommend using int for quantity if possible. If not possible, then format the quantities to identical format (including certain digit rounding).

huangapple
  • 本文由 发表于 2021年10月28日 15:44:37
  • 转载请务必保留本文链接:https://go.coder-hub.com/69750094.html
匿名

发表评论

匿名网友

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

确定