英文:
How to recursively loop through map using different data structures
问题
我正在尝试找出在Go语言中递归遍历[string]int
映射的最佳方法。我正在构建一个游戏,其中涉及多个国家,并最终按两个一组进行分组。
目标是将前两个得分最低的国家匹配到一个自己的组中,并将其添加回集合中,使新映射的总值为这些国家的得分之和。
然后对所有组递归执行此操作,最终得到一个组和一个总值。
例如,如果你有:
score := map[string]int{
"Canada": 7,
"US": 2,
"Germany": 3,
"Korea": 4,
}
group1 = {[US:2] [Germany:3]}
,总值为5
现在,group1将以得分为5的形式放回初始集合中,因为它取得了最低的两个得分。现在我们有:
score := map[string]int{
"Canada": 7,
"Korea": 4,
group1: `US:2 Germany:3`,总值为5
}
如果这现在是集合中最低的得分,下一次迭代将是:
group2 = {[Korea:4] [group1:5]}
score := map[string]int{
"Canada": 7,
group2: `Korea:4 group1:5`,总值为9
}
依此类推,直到最后只剩下一个组。我认为基本结构应该是这样的。然而,由于数据结构现在包含了一个[string]int
映射以及这个新映射,我不确定如何正确地做这个。
我意识到这不是一个非常通用的问题,但是可以使用接口吗?我对Go语言非常陌生,所以希望能得到一些建议。
这里有一个示例进一步说明我的意思:
https://play.golang.org/p/cnkTc0HBY4
英文:
I'm trying to figure out the best way to recursively go through a [string]int
map in Go. I'm building a game in which multiple countries are involved, and grouped together by teams of two in the end.
The goal is to match the first two countries with the lowest 'score' into its own group of two, and add it back to the collection giving the new map a total value of the scores of those countries.
Then recursively doing that to all the groups, ending up with one group and one total value in the end.
For example, if you had:
score := map[string]int{
"Canada": 7,
"US": 2,
"Germany": 3,
"Korea": 4,
}
group1 = {[US:2] [Germany:3]}
with a total of 5
group1 would now be put back into the initial collection with a 'score' of 5 since it takes the two lowest scores. We would now have:
score := map[string]int{
"Canada": 7,
"Korea": 4,
group1: `US:2 Germany:3` with a total of 5
}
If this was now the lowest score in the collection, the next iteration would be:
group2 = {[Korea:4] [group1:5]}
score := map[string]int{
"Canada": 7,
group2: `Korea:4 group1:5` with a total of 9
}
And so on until you're left with one.. I think the basic structure should be something like this. However, I'm unsure of the proper way to do this since the data structure is now encompassing a [string]int
map, as well as this new map.
I realize this is not such a generic question, but could an interface be used for this? I'm very new to Go, so advice would be helpful.
Here is an example to further illustrate what I mean:
https://play.golang.org/p/cnkTc0HBY4
答案1
得分: 2
你的问题可以通过使用堆数据结构来“轻松”解决。
package main
import (
"container/heap"
"fmt"
)
// 具有分数的对象
type Scoreable interface {
fmt.Stringer
Score() int
}
// 国家有一个名称和一个分数
type Country struct {
name string
score int
}
// Country 实现了 Scoreable 接口
func (c Country) Score() int {
return c.score
}
// ... 还有 fmt.Stringer 接口
func (c Country) String() string {
return fmt.Sprintf("%s [%d]", c.name, c.score)
}
// 团队由两个 Scoreable 对象组成,并且有自己的分数
type Team struct {
team1, team2 Scoreable
score int
}
// Team 实现了 Scoreable 接口
func (t Team) Score() int {
return t.score
}
// ... 还有 fmt.Stringer 接口
func (t Team) String() string {
return fmt.Sprintf("(%s + %s)", t.team1.String(), t.team2.String())
}
// 使用 Scoreable 对象的切片来实现堆
type TeamHeap []Scoreable
// TeamHeap 实现了 heap.Interface 接口
func (th TeamHeap) Len() int {
return len(th)
}
func (th TeamHeap) Less(i, j int) bool {
return th[i].Score() < th[j].Score()
}
func (th TeamHeap) Swap(i, j int) {
th[i], th[j] = th[j], th[i]
}
func (th *TeamHeap) Push(t interface{}) {
*th = append(*th, t.(Scoreable))
}
func (th *TeamHeap) Pop() interface{} {
old := *th
n := len(old)
t := old[n-1]
*th = old[0 : n-1]
return t
}
// 主函数
func main() {
// 创建一个堆并初始化
teams := &TeamHeap{}
heap.Init(teams)
// 将国家推入堆中(注意:使用 heap.Push(),而不是 teams.Push())
heap.Push(teams, Country{"Canada", 7})
heap.Push(teams, Country{"US", 2})
heap.Push(teams, Country{"Germany", 3})
heap.Push(teams, Country{"Korea", 4})
// 取出两个分数最低的团队,并将它们组成一个新的团队
// 重复此过程,直到只剩下一个团队
for teams.Len() > 1 {
t1 := heap.Pop(teams).(Scoreable)
t2 := heap.Pop(teams).(Scoreable)
heap.Push(teams, Team{t1, t2, t1.Score() + t2.Score()})
}
// 打印现在在堆中的团队
for teams.Len() > 0 {
t := heap.Pop(teams).(Team)
fmt.Println(t)
}
}
你可以在 Go Playground 上找到可运行的代码。
英文:
Your problem can "easy" be solved using a heap data structure.
package main
import (
"container/heap"
"fmt"
)
// Something that has a score
type Scoreable interface {
fmt.Stringer
Score() int
}
// A country has a name and a score
type Country struct {
name string
score int
}
// Country implements Scoreable
func (c Country) Score() int {
return c.score
}
// ... and fmt.Stringer
func (c Country) String() string {
return fmt.Sprintf("%s [%d]", c.name, c.score)
}
// A team consists of two Scoreable's and has itself a score
type Team struct {
team1, team2 Scoreable
score int
}
// Team implements Scoreable
func (t Team) Score() int {
return t.score
}
// ... and fmt.Stringer
func (t Team) String() string {
return fmt.Sprintf("(%s + %s)", t.team1.String(), t.team2.String())
}
// The heap will be implemented using a slice of Scoreables
type TeamHeap []Scoreable
// TeamHeap implements heap.Interface
func (th TeamHeap) Len() int {
return len(th)
}
func (th TeamHeap) Less(i, j int) bool {
return th[i].Score() < th[j].Score()
}
func (th TeamHeap) Swap(i, j int) {
th[i], th[j] = th[j], th[i]
}
func (th *TeamHeap) Push(t interface{}) {
*th = append(*th, t.(Scoreable))
}
func (th *TeamHeap) Pop() interface{} {
old := *th
n := len(old)
t := old[n-1]
*th = old[0 : n-1]
return t
}
// The main function
func main() {
// Create a heap and initialize it
teams := &TeamHeap{}
heap.Init(teams)
// Push the countries (NB: heap.Push(), not teams.Push())
heap.Push(teams, Country{"Canada", 7})
heap.Push(teams, Country{"US", 2})
heap.Push(teams, Country{"Germany", 3})
heap.Push(teams, Country{"Korea", 4})
// Take the two teams with lowest score and make a new team of them
// Repeat this until there's only one team left
for teams.Len() > 1 {
t1 := heap.Pop(teams).(Scoreable)
t2 := heap.Pop(teams).(Scoreable)
heap.Push(teams, Team{t1, t2, t1.Score() + t2.Score()})
}
// Print the teams that we now have in the heap
for teams.Len() > 0 {
t := heap.Pop(teams).(Team)
fmt.Println(t)
}
}
You can find runnable code on the Go Playground.
答案2
得分: 2
package main
import (
"container/heap"
"fmt"
)
//递归数据结构可能看起来像这样
type Group struct {
Score int
Left *Group
Right *Group
Country string
}
//您可以使用切片将它们组织成树
type GrHeap []Group
//要实现您的逻辑,可以使用stdlib/container/heap Heap接口
//您必须为切片实现Heap接口
func (h GrHeap) Len() int { return len(h) }
func (h GrHeap) Less(i, j int) bool { return h[i].Score < h[j].Score }
func (h GrHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] }
func (h *GrHeap) Push(x interface{}) {
// Push和Pop使用指针接收器,因为它们修改切片的长度,
// 而不仅仅是其内容。
*h = append(*h, x.(Group))
}
func (h *GrHeap) Pop() interface{} {
old := *h
n := len(old)
x := old[n-1]
*h = old[0 : n-1]
return x
}
func main() {
//您很可能已经有一个映射
//无论如何,保留它以便方便访问各个国家
score := map[string]int{
"Canada": 7,
"US": 2,
"Germany": 3,
"Korea": 4,
}
//在这里我们分配堆
gr := make(GrHeap, 0)
//从映射中填充堆
for k, v := range score {
g := Group{v, nil, nil, k}
gr = append(gr, g)
}
//并初始化
heap.Init(&gr)
//在这里我们使用堆的魔力来实现您的逻辑
for len(gr) > 2 {
l := heap.Pop(&gr).(Group)
r := heap.Pop(&gr).(Group)
ng := Group{l.Score + r.Score, &l, &r, ""}
heap.Push(&gr, ng)
}
fmt.Println(gr)
fmt.Println(gr[1].Left)
fmt.Println(gr[1].Right.Left)
//您可以看到它的工作原理 https://play.golang.org/p/gugJxJb7rr
}
以上是给定代码的翻译结果。
英文:
package main
import (
"container/heap"
"fmt"
)
//Recursive data structure may looks something like
type Group struct {
Score int
Left *Group
Right *Group
Country string
}
//You can use slice to hold them organized in tree
type GrHeap []Group
//To implement your logic you can use stdlib/container/heap Heap interface
//you must implement Heap interface for your slice
func (h GrHeap) Len() int { return len(h) }
func (h GrHeap) Less(i, j int) bool { return h[i].Score < h[j].Score }
func (h GrHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] }
func (h *GrHeap) Push(x interface{}) {
// Push and Pop use pointer receivers because they modify the slice's length,
// not just its contents.
*h = append(*h, x.(Group))
}
func (h *GrHeap) Pop() interface{} {
old := *h
n := len(old)
x := old[n-1]
*h = old[0 : n-1]
return x
}
func main() {
//you most likely already have a map
//anyway it will be handy to keep it for convenient access to individual country
score := map[string]int{
"Canada": 7,
"US": 2,
"Germany": 3,
"Korea": 4,
}
//here we allocate heap
gr := make(GrHeap, 0)
//populate it from map
for k, v := range score {
g := Group{v, nil, nil, k}
gr = append(gr, g)
}
//and initialize
heap.Init(&gr)
//and here we use heap magic to implement your logic
for len(gr) > 2 {
l := heap.Pop(&gr).(Group)
r := heap.Pop(&gr).(Group)
ng := Group{l.Score + r.Score, &l, &r, ""}
heap.Push(&gr, ng)
}
fmt.Println(gr)
fmt.Println(gr[1].Left)
fmt.Println(gr[1].Right.Left)
//and you can see it works https://play.golang.org/p/gugJxJb7rr
}
答案3
得分: 0
你可以尝试使用map[string]interface{}
和类型断言(Type assertion)
。以下是示例代码:
package main
import "fmt"
const total = "total"
func GetValue(i interface{}) int {
value, ok := i.(int)
if ok {
return value
}
return i.(map[string]interface{})[total].(int)
}
func main() {
score := map[string]interface{}{
"Canada": 7,
"US": 2,
"Germany": 3,
"Korea": 4,
}
groupCount := 0
for len(score) > 2 {
var (
firstMin = math.MaxInt32
secondMin = math.MaxInt32
firstKey = ""
secondKey = ""
)
for k, v := range score {
iv := GetValue(v)
if iv < firstMin {
secondMin = firstMin
secondKey = firstKey
firstMin = iv
firstKey = k
continue
}
if iv < secondMin {
secondMin = iv
secondKey = k
continue
}
}
groupCount++
score[fmt.Sprintf("Group%d", groupCount)] = map[string]interface{}{
firstKey: score[firstKey],
secondKey: score[secondKey],
total: GetValue(score[firstKey]) + GetValue(score[secondKey]),
}
delete(score, firstKey)
delete(score, secondKey)
}
fmt.Println(score)
}
你可以在这个链接中查看代码:https://play.golang.org/p/qq5qwAsh1m
英文:
You can try map[string]interface{}
with Type assertion
。
Here is the demo
package main
import "fmt"
const total = "total"
func GetValue(i interface{}) int {
value, ok := i.(int)
if ok {
return value
}
return i.(map[string]interface{})[total].(int)
}
func main() {
score := map[string]interface{}{
"Canada": 7,
"US": 2,
"Germany": 3,
"Korea": 4,
}
groupCount := 0
for len(score) > 2 {
var (
firstMin = math.MaxInt32
secondMin = math.MaxInt32
firstKey = ""
secondKey = ""
)
for k, v := range score {
iv := GetValue(v)
if iv < firstMin {
secondMin = firstMin
secondKey = firstKey
firstMin = iv
firstKey = k
continue
}
if iv < secondMin {
secondMin = iv
secondKey = k
continue
}
}
groupCount++
score[fmt.Sprintf("Group%d", groupCount)] = map[string]interface{}{
firstKey: score[firstKey],
secondKey: score[secondKey],
total: GetValue(score[firstKey])+ GetValue(score[secondKey]),
}
delete(score, firstKey)
delete(score, secondKey)
}
fmt.Println(score)
}
Here is the link https://play.golang.org/p/qq5qwAsh1m
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论