这是古老的“为什么我的地图打印乱序”问题的变体。
我有一个(相当大)数量的map[MyKey]MyValue
形式的地图,其中MyKey
和MyValue
是(通常)结构。我对所有关键类型都有“少”功能。
我需要按顺序遍历地图。 (具体来说,由该类型的less函数定义的顺序。)现在,我的代码如下所示:
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)
}
然后,每当我想要有序迭代时,它看起来像:
var m map[MyKey]MyValue
m = GetMapFromSomewhereUseful()
for _, kv := range NewPairKeyValueSlice(m) {
key := kv.MyKey
value := kv.MyValue
DoUsefulWork(key, value)
}
这看起来很有用。问题是它非常冗长。特别是因为手头的问题实际上与有序地图的实现无关,而且实际上是关于循环中的有用工作。
另外,我有几种不同的键和值类型。因此,每次我想按顺序遍历地图时,我都会复制/粘贴所有代码并使用新密钥查找/替换MyKey
,并使用新值查找/ MyValue
。复制/粘贴这个量级是......“臭”。它已经变得麻烦了,因为我已经犯了一些错误,我必须多次修复。
这种技术的缺点还在于需要制作所有键和值的完整副本。这是不可取的,但我没有看到解决方法。 (我可以将它简化为键,但它不会改变问题的主要性质。)
This question正在尝试用字符串做同样的事情。 This question用字符串和整数来做。 This question意味着您需要使用反射,并且必须有一个switch语句来切换每种可能的类型,包括所有用户定义的类型。
但是,如果人们对地图不能确定性地进行迭代感到困惑,那么似乎必须有更好的解决方案来解决这个问题。我来自OO背景,所以我可能遗漏了一些基本的东西。
那么,是否有合理的方法按顺序迭代地图?
更新:编辑问题以获得有关来源的更多信息,以防有更好的解决方案。
我需要为输出分组。每个分组级别都采用如下结构:
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
}
然后,我将遍历ObjTypeTree
中的子项以打印类型分组。对于其中的每一个,我遍历ObjKindTree
以打印Kind分组。迭代是使用类型的方法完成的,每种类型都需要一种不同的方式来打印其分组级别。需要按顺序打印组,这会导致问题。
答案 0 :(得分:2)
如果需要密钥整理,请勿使用地图。使用B树或任何其他/类似订购的容器。
答案 1 :(得分:2)
我是第二个jnml的回答。但是如果你想要比你更短的东西并且愿意放弃编译时类型安全,那么my library可能对你有用。 (它建立在reflect
之上。)这是一个完整的例子:
package main
import (
"fmt"
"github.com/BurntSushi/ty/fun"
)
type OrderedKey struct {
L1 rune
L2 rune
}
func (k1 OrderedKey) Less(k2 OrderedKey) bool {
return k1.L1 < k2.L1 || (k1.L1 == k2.L1 && k1.L2 < k2.L2)
}
func main() {
m := map[OrderedKey]string{
OrderedKey{'b', 'a'}: "second",
OrderedKey{'x', 'y'}: "fourth",
OrderedKey{'x', 'x'}: "third",
OrderedKey{'a', 'b'}: "first",
OrderedKey{'x', 'z'}: "fifth",
}
for k, v := range m {
fmt.Printf("(%c, %c): %s\n", k.L1, k.L2, v)
}
fmt.Println("-----------------------------")
keys := fun.QuickSort(OrderedKey.Less, fun.Keys(m)).([]OrderedKey)
for _, k := range keys {
v := m[k]
fmt.Printf("(%c, %c): %s\n", k.L1, k.L2, v)
}
}
请注意,这种方法会比较慢,所以如果你需要性能,这不是一个好的选择。