如果地图不能在Go lang中排序,那么正确的方法是什么?

时间:2014-08-17 15:34:24

标签: go

我们说我有一个字符串,我想计算每个字母的频率,然后按频率对表格进行排序。期望的输出"你好拉里"将是:

+--------+-----------+
| Letter | Occurence |
+--------+-----------+
| l      |         3 |
| r      |         2 |
| h      |         1 |
| e      |         1 |
| o      |         1 |
| a      |         1 |
| y      |         1 |
+--------+-----------+

首先我想我会使用字母作为键的 map 轻松处理这个问题。这真的很容易。但是,地图项目不能have an order因此无法排序。

我想我可以使用结构处理这个问题:

type Letter struct {
    Value string
    Score int
}
type LetterList []Letter

然而,这带来了许多其他问题:

  1. 我需要检查LetterList中是否已存在Letter,因为我不能将这些字母用作键
  2. 没有直接的方式对它们进行排序(使用Int.sort()左右)
  3. 使用这些结构根本不会感觉很优雅。有更好的解决方案吗?

1 个答案:

答案 0 :(得分:3)

您会惊讶地发现在一个小切片上快速有效地循环,并且您可以在其上实现排序相当简单。

我建议阅读http://golang.org/pkg/sort/ SortWrapper。

type Letter struct {
    Value rune
    Score int
}

type LetterList []*Letter

func (ll *LetterList) FindOrAdd(r rune) (l *Letter) {
    for _, l = range *ll {
        if l.Value == r {
            return
        }
    }
    l = &Letter{Value: r, Score: 0}
    *ll = append(*ll, l)
    return
}

func (ll LetterList) SortByScore() LetterList {
    sort.Sort(llByScore{ll})
    return ll
}

func (ll LetterList) SortByValue() LetterList {
    sort.Sort(llByValue{ll})
    return ll
}

func (ll LetterList) String() string {
    var b bytes.Buffer
    b.WriteByte('[')
    for _, v := range ll {
        b.WriteString(fmt.Sprintf("{%q, %d}, ", v.Value, v.Score))
    }
    b.WriteByte(']')
    return b.String()

}

func New(s string) (ll LetterList) {
    ll = LetterList{}
    for _, r := range s {
        ll.FindOrAdd(r).Score++
    }
    return
}

func (ll LetterList) Len() int      { return len(ll) }
func (ll LetterList) Swap(i, j int) { ll[i], ll[j] = ll[j], ll[i] }

type llByScore struct{ LetterList }

func (l llByScore) Less(i, j int) bool {
    return l.LetterList[i].Score > l.LetterList[j].Score
}

type llByValue struct{ LetterList }

func (l llByValue) Less(i, j int) bool {
    return l.LetterList[i].Value > l.LetterList[j].Value
}

func main() {
    ll := New(`Let's say I have a string and I would like to count each letter's frequency and then sort the table by the frequency. Desired output of "hello larry" would be`)
    fmt.Println(ll)
    fmt.Println(ll.SortByScore())
    fmt.Println(ll.SortByValue())
}

playground

另一种方法是使用地图然后进行排序从中生成一个列表并对其进行排序。