如何使用不同的数据结构递归循环遍历地图

时间:2017-08-30 15:11:58

标签: go

我正试图找出在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` with a total of 5
}

如果这是集合中的最低分,那么下一次迭代将是:

group2 = {[Korea:4] [group1:5]}

 score := map[string]int{
            "Canada": 7,
            group2: `Korea:4 group1:5` with a total of 9
  }

依此类推,直到你留下一个......我认为基本结构应该是这样的。但是,我不确定这样做的正确方法,因为数据结构现在包含[string]int地图以及这个新地图。

我意识到这不是一个通用的问题,但可以使用接口吗?我是Go的新手,所以建议会有所帮助。

这是一个进一步说明我的意思的例子: https://play.golang.org/p/cnkTc0HBY4

3 个答案:

答案 0 :(得分:2)

你的问题可以很容易"使用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)
    }
}

您可以在Go Playground找到runnable code

答案 1 :(得分:2)

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
}

答案 2 :(得分: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