如何正确分组数据以获得树结构?
How to group data correctly to get a tree structure?
在 golang 应用程序中,我查询了这样的 table:
| ID | AGG_YEAR | AGG_MONTH | GENDER | AGE_RANGE | INCOME_RANGE | TOTAL |
|-----------|----------|-----------|--------|-----------|--------------|-------|
| 107502389 | 2019 | 7 | F | 18_29 | 1000_2000 | 15 |
| 107502389 | 2019 | 7 | F | 18_29 | 2000_4000 | 42 |
| 107502389 | 2019 | 7 | F | 30_44 | 1000_2000 | 25 |
| 107502389 | 2019 | 7 | F | 30_44 | 2000_4000 | 63 |
| 107502389 | 2019 | 7 | M | 18_29 | 1000_2000 | 30 |
| 107502389 | 2019 | 7 | M | 18_29 | 2000_4000 | 18 |
| 107502389 | 2019 | 7 | M | 30_44 | 1000_2000 | 36 |
| 107502389 | 2019 | 7 | M | 30_44 | 2000_4000 | 19 |
这个table存储了某个月某个工资水平的男性和女性总数的信息。通常,查询数据库后,每条记录都会被一条一条地解析:
type Entry struct {
ID int `json:"id"`
AggYear int `json:"agg_year"`
AggMonth int `json:"agg_month"`
Gender string `json:"gender"`
AgeRange string `json:"age_range"`
IncomeRange string `json:"income_range"`
Total int `json:"total"`
}
var entries []Entry
rows, err := database.Query("***"); if err != nil {
fmt.Println(err)
return
}
defer rows.Close()
for rows.Next() {
var entry Entry
if err = rows.Scan(&entry.ID, &entry.AggMethod, &entry.AggYear, &entry.AggMonth, &entry.Gender, &entry.AgeRange, &entry.IncomeRange, &entry.Total); err != nil {
fmt.Println(err)
return
}
entries = append(entries, entry)
}
type IncomeDetails struct {
IncomeRange string `json:"income_range"`
Total int `json:"total"`
}
type AgeDetails struct {
AgeRange string `json:"age_range"`
Details []IncomeDetails `json:"details"`
}
type GenderDetails struct {
Gender string `json:"gender"`
Details []AgeDetails `json:"details"`
}
type EntryDetails struct {
AggYear int `json:"agg_year"`
AggMonth int `json:"agg_month"`
Details []GenderDetails `json:"details"`
}
type DataEntry struct {
ID int `json:"id"`
Details []EntryDetails `json:"details"`
}
var entryDetails []EntryDetails
i:= 0
for i < len(entries) {
var genderDetails []GenderDetails
aggYear := entries[i].AggYear
aggMonth := entries[i].AggMonth
for aggYear == entries[i].AggYear && aggMonth == entries[i].AggMonth {
gender := entries[i].Gender
var ageDetails []AgeDetails
for gender == entries[i].Gender {
ageRange := entries[i].AgeRange
var incomeDetails []IncomeDetails
for ageRange == entries[i].AgeRange && gender == entries[i].Gender { // <- runtime error: index out of range
incomeDetail := IncomeDetails{entries[i].IncomeRange, entries[i].Total}
incomeDetails = append(incomeDetails, incomeDetail)
i++
}
ageDetail := AgeDetails{entries[i-1].AgeRange, incomeDetails}
ageDetails = append(ageDetails, ageDetail)
i++
}
genderDetail := GenderDetails{entries[i-1].Gender, ageDetails}
genderDetails = append(genderDetails, genderDetail)
i++
}
entryDetail := EntryDetails{entries[i-1].AggYear, entries[i-1].AggMonth, genderDetails}
entryDetails = append(entryDetails, entryDetail)
i++
}
我想知道将以下值分组的最佳方法,如下例所示?我想了解操作的顺序。我将不胜感激。
[
{
"id": 107502389,
"details": [
{
"agg_year": 2019,
"agg_month": 7,
"details": [
{
"gender": "F",
"details": [
{
"age_range": "18_29",
"details": [
{
"income_range": "1000_2000",
"total": "15"
},
{
"income_range": "2000_4000",
"total": "42"
},
]
},
{
"age_range": "30_44",
"details": [
{
"income_range": "1000_2000",
"total": "25"
},
{
"income_range": "2000_4000",
"total": "63"
},
]
}
]
},
{
"gender": "M",
"details": [
{
"age_range": "18_29",
"details": [
{
"income_range": "1000_2000",
"total": "30"
},
{
"income_range": "2000_4000",
"total": "18"
},
]
},
{
"age_range": "30_44",
"details": [
{
"income_range": "1000_2000",
"total": "36"
},
{
"income_range": "2000_4000",
"total": "19"
},
]
}
]
}
]
}
]
}
]
通常,我会根据我想要的响应更新结构。例如,在您的情况下,它将是:
type DataEntry struct {
ID int `json:"id"`
Details []EntryDetails `json:"details"`
}
type EntryDetails struct {
AggYear int `json:"agg_year"`
AggMonth int `json:"agg_month"`
Details []GenderDetails `json:"details"`
}
type GenderDetails struct {
Gender string `json:"gender"`
Details []AgeDetails `json:"details"`
}
type AgeDetails struct {
AgeRange string `json:"age_range"`
Details []IncomeDetails `json:"details"`
}
type IncomeDetails struct {
IncomeRange string `json:"income_range"`
Total int `json:"total"`
}
将您的代码分成更小的部分总是更容易阅读和维护。
下一部分将详细信息添加到结构中:您应该根据要求查询您的代码以逐一填充结构。例如:首先是 getID-'Entry struct',然后是 ID-'EntryDetails struct' 的 getAggYear 和 getAggMonth,依此类推。
您可以在这里找到完整的工作程序:https://play.golang.org/p/_pdb5y9Wd-O
尽情享受吧!
在 golang 应用程序中,我查询了这样的 table:
| ID | AGG_YEAR | AGG_MONTH | GENDER | AGE_RANGE | INCOME_RANGE | TOTAL |
|-----------|----------|-----------|--------|-----------|--------------|-------|
| 107502389 | 2019 | 7 | F | 18_29 | 1000_2000 | 15 |
| 107502389 | 2019 | 7 | F | 18_29 | 2000_4000 | 42 |
| 107502389 | 2019 | 7 | F | 30_44 | 1000_2000 | 25 |
| 107502389 | 2019 | 7 | F | 30_44 | 2000_4000 | 63 |
| 107502389 | 2019 | 7 | M | 18_29 | 1000_2000 | 30 |
| 107502389 | 2019 | 7 | M | 18_29 | 2000_4000 | 18 |
| 107502389 | 2019 | 7 | M | 30_44 | 1000_2000 | 36 |
| 107502389 | 2019 | 7 | M | 30_44 | 2000_4000 | 19 |
这个table存储了某个月某个工资水平的男性和女性总数的信息。通常,查询数据库后,每条记录都会被一条一条地解析:
type Entry struct {
ID int `json:"id"`
AggYear int `json:"agg_year"`
AggMonth int `json:"agg_month"`
Gender string `json:"gender"`
AgeRange string `json:"age_range"`
IncomeRange string `json:"income_range"`
Total int `json:"total"`
}
var entries []Entry
rows, err := database.Query("***"); if err != nil {
fmt.Println(err)
return
}
defer rows.Close()
for rows.Next() {
var entry Entry
if err = rows.Scan(&entry.ID, &entry.AggMethod, &entry.AggYear, &entry.AggMonth, &entry.Gender, &entry.AgeRange, &entry.IncomeRange, &entry.Total); err != nil {
fmt.Println(err)
return
}
entries = append(entries, entry)
}
type IncomeDetails struct {
IncomeRange string `json:"income_range"`
Total int `json:"total"`
}
type AgeDetails struct {
AgeRange string `json:"age_range"`
Details []IncomeDetails `json:"details"`
}
type GenderDetails struct {
Gender string `json:"gender"`
Details []AgeDetails `json:"details"`
}
type EntryDetails struct {
AggYear int `json:"agg_year"`
AggMonth int `json:"agg_month"`
Details []GenderDetails `json:"details"`
}
type DataEntry struct {
ID int `json:"id"`
Details []EntryDetails `json:"details"`
}
var entryDetails []EntryDetails
i:= 0
for i < len(entries) {
var genderDetails []GenderDetails
aggYear := entries[i].AggYear
aggMonth := entries[i].AggMonth
for aggYear == entries[i].AggYear && aggMonth == entries[i].AggMonth {
gender := entries[i].Gender
var ageDetails []AgeDetails
for gender == entries[i].Gender {
ageRange := entries[i].AgeRange
var incomeDetails []IncomeDetails
for ageRange == entries[i].AgeRange && gender == entries[i].Gender { // <- runtime error: index out of range
incomeDetail := IncomeDetails{entries[i].IncomeRange, entries[i].Total}
incomeDetails = append(incomeDetails, incomeDetail)
i++
}
ageDetail := AgeDetails{entries[i-1].AgeRange, incomeDetails}
ageDetails = append(ageDetails, ageDetail)
i++
}
genderDetail := GenderDetails{entries[i-1].Gender, ageDetails}
genderDetails = append(genderDetails, genderDetail)
i++
}
entryDetail := EntryDetails{entries[i-1].AggYear, entries[i-1].AggMonth, genderDetails}
entryDetails = append(entryDetails, entryDetail)
i++
}
我想知道将以下值分组的最佳方法,如下例所示?我想了解操作的顺序。我将不胜感激。
[
{
"id": 107502389,
"details": [
{
"agg_year": 2019,
"agg_month": 7,
"details": [
{
"gender": "F",
"details": [
{
"age_range": "18_29",
"details": [
{
"income_range": "1000_2000",
"total": "15"
},
{
"income_range": "2000_4000",
"total": "42"
},
]
},
{
"age_range": "30_44",
"details": [
{
"income_range": "1000_2000",
"total": "25"
},
{
"income_range": "2000_4000",
"total": "63"
},
]
}
]
},
{
"gender": "M",
"details": [
{
"age_range": "18_29",
"details": [
{
"income_range": "1000_2000",
"total": "30"
},
{
"income_range": "2000_4000",
"total": "18"
},
]
},
{
"age_range": "30_44",
"details": [
{
"income_range": "1000_2000",
"total": "36"
},
{
"income_range": "2000_4000",
"total": "19"
},
]
}
]
}
]
}
]
}
]
通常,我会根据我想要的响应更新结构。例如,在您的情况下,它将是:
type DataEntry struct {
ID int `json:"id"`
Details []EntryDetails `json:"details"`
}
type EntryDetails struct {
AggYear int `json:"agg_year"`
AggMonth int `json:"agg_month"`
Details []GenderDetails `json:"details"`
}
type GenderDetails struct {
Gender string `json:"gender"`
Details []AgeDetails `json:"details"`
}
type AgeDetails struct {
AgeRange string `json:"age_range"`
Details []IncomeDetails `json:"details"`
}
type IncomeDetails struct {
IncomeRange string `json:"income_range"`
Total int `json:"total"`
}
将您的代码分成更小的部分总是更容易阅读和维护。
下一部分将详细信息添加到结构中:您应该根据要求查询您的代码以逐一填充结构。例如:首先是 getID-'Entry struct',然后是 ID-'EntryDetails struct' 的 getAggYear 和 getAggMonth,依此类推。
您可以在这里找到完整的工作程序:https://play.golang.org/p/_pdb5y9Wd-O
尽情享受吧!