doumei7420 2013-06-18 22:09
浏览 33
已采纳

有没有一种简单的方法可以依次遍历地图?

This is a variant of the venerable "why is my map printing out of order" question.

I have a (fairly large) number of maps of the form map[MyKey]MyValue, where MyKey and MyValue are (usually) structs. I've got "less" functions for all the key types.

I need to iterate over the maps in order. (Specifically, the order defined by the less function on that type.) Right now, my code looks like this:

type PairKeyValue struct {
    MyKey
    MyValue
}

type PairKeyValueSlice []Pair

func (ps PairKeyValueSlice) Len() int {
    return len(ps)
}

func (ps PairKeyValueSlice) Swap(i,j int) {
    ps[i], ps[j] = ps[j], ps[i]
}

func (ps PairKeyValueSlice) Less(i,j int) {
    return LessKey(ps[i].MyKey, ps[j].MyKey)
}

func NewPairKeyValueSlice(m map[MyKey]MyValue) (ps PairKeyValueSlice) {
    ps = make(PairKeyValueSlice, len(m))
    i := 0
    for k,v := range m {
        ps[i] = PairKeyValue{k,v}
        i++
    }
    sort.Sort(ps)
}

And then, any time I want an in-order iteration, it looks like:

var m map[MyKey]MyValue
m = GetMapFromSomewhereUseful()
for _, kv := range NewPairKeyValueSlice(m) {
    key := kv.MyKey
    value := kv.MyValue
    DoUsefulWork(key, value)
}

And this appears to largely work. The problem is that it is terribly verbose. Particularly since the problem at hand really has very little to do with implmenting ordered maps and is really about the useful work in the loop.

Also, I have several different keys and value types. So, every time I want to iterate over a map in order, I copy/paste all that code and do find/replace MyKey with the new key and MyValue with the new value. Copy/paste on that magnitude is... "smelly". It has already become a hassle, since I've already made a few errors that I had to fix several times.

This technique also has the downside that it requires making a full copy of all the keys and values. That is undesirable, but I don't see a way around it. (I could reduce it to just the keys, but it doesn't change the primary nature of the problem.)

This question is attempting the same thing with strings. This question does it with strings and ints. This question implies that you need to use reflection and will have to have a switch statement that switches on every possible type, including all user-defined types.

But with the people who are puzzled that maps don't iterate deterministically, it seems that there has got to be a better solution to this problem. I'm from an OO background, so I'm probably missing something fundamental.

So, is there a reasonable way to iterate over a map in order?


Update: Editing the question to have more information about the source, in case there's a better solution than this.

I have a lot of things I need to group for output. Each grouping level is in a structure that looks like these:

type ObjTypeTree struct {
    Children map[Type]*ObjKindTree
    TotalCount uint
}
type ObjKindTree struct {
    Children map[Kind]*ObjAreaTree
    TotalCount uint
}
type ObjAreaTree struct {
    Children map[Area]*ObjAreaTree
    TotalCount uint
    Objs []*Obj
}

Then, I'd iterate over the children in the ObjTypeTree to print the Type groupings. For each of those, I iterate over the ObjKindTree to print the Kind groupings. The iterations are done with methods on the types, and each kind of type needs a little different way of printing its grouping level. Groups need to be printed in order, which causes the problem.

  • 写回答

2条回答 默认 最新

  • dongzhui9936 2013-06-18 22:40
    关注

    Don't use a map if key collating is required. Use a B-tree or any other/similar ordered container.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 BP神经网络控制倒立摆
  • ¥20 要这个数学建模编程的代码 并且能完整允许出来结果 完整的过程和数据的结果
  • ¥15 html5+css和javascript有人可以帮吗?图片要怎么插入代码里面啊
  • ¥30 Unity接入微信SDK 无法开启摄像头
  • ¥20 有偿 写代码 要用特定的软件anaconda 里的jvpyter 用python3写
  • ¥20 cad图纸,chx-3六轴码垛机器人
  • ¥15 移动摄像头专网需要解vlan
  • ¥20 access多表提取相同字段数据并合并
  • ¥20 基于MSP430f5529的MPU6050驱动,求出欧拉角
  • ¥20 Java-Oj-桌布的计算