Golang Sort 为 map 添加了额外的值

huangapple go评论85阅读模式
英文:

Golang Sort adds extra values to map

问题

上面是我要翻译的内容:

type GeoNameTally struct {
    Id    uint32
    Count uint32
}

type Tally map[uint32]GeoNameTally

上面是我拥有的结构体。这个想法非常简单,我只是在计算某个元素出现的次数。

func (t Tally) Len() int           { return len(t) }
func (t Tally) Less(i, j int) bool { return t[uint32(i)].Count < t[uint32(j)].Count }
func (t Tally) Swap(i, j int)      { t[uint32(i)], t[uint32(j)] = t[uint32(j)], t[uint32(i)] }

在排序之前,一切都运行得很正常。在排序之前,地图看起来很好:

map[1043487:{Id:1043487 Count:1} 1043503:{Id:1043503 Count:1} 1043444:{Id:1043444 Count:1} 1043491:{Id:1043491 Count:1} 1043459:{Id:1043459 Count:1} 1043475:{Id:1043475 Count:1} 1043464:{Id:1043464 Count:1} 1043441:{Id:1043441 Count:1} 1043470:{Id:1043470 Count:1} 1043460:{Id:1043460 Count:1}]

然而,在sort.Sort(myTally)之后,地图中出现了额外的空值,如下所示:

map[1043503:{Id:1043503 Count:1} 1043491:{Id:1043491 Count:1} 1043459:{Id:1043459 Count:1} 1043475:{Id:1043475 Count:1} 4:{Id:0 Count:0} 8:{Id:0 Count:0} 1043487:{Id:1043487 Count:1} 1:{Id:0 Count:0} 5:{Id:0 Count:0} 9:{Id:0 Count:0} 1043470:{Id:1043470 Count:1} 2:{Id:0 Count:0} 6:{Id:0 Count:0} 1043444:{Id:1043444 Count:1} 1043441:{Id:1043441 Count:1} 1043460:{Id:1043460 Count:1} 3:{Id:0 Count:0} 7:{Id:0 Count:0} 1043464:{Id:1043464 Count:1}]

我在这三个函数中做错了什么吗?

英文:
type GeoNameTally struct {
	Id    uint32
	Count uint32
}

type Tally map[uint32]GeoNameTally

Above are the structs i have. The idea is pretty simple. I'm just tallying how many times something occurs.

func (t Tally) Len() int           { return len(t) }
func (t Tally) Less(i, j int) bool { return t[uint32(i)].Count &lt; t[uint32(j)].Count }
func (t Tally) Swap(i, j int)      { t[uint32(i)], t[uint32(j)] = t[uint32(j)], t[uint32(i)] }

Everything works perfectly fine until I get to the sort. Right before sort, the map looks fine:

map[1043487:{Id:1043487 Count:1} 1043503:{Id:1043503 Count:1} 1043444:{Id:1043444 Count:1} 1043491:{Id:1043491 Count:1} 1043459:{Id:1043459 Count:1} 1043475:{Id:1043475 Count:1} 1043464:{Id:1043464 Count:1} 1043441:{Id:1043441 Count:1} 1043470:{Id:1043470 Count:1} 1043460:{Id:1043460 Count:1}]

However right after sort.Sort(myTally) the map has extra and empty values as you can see from the following output:

map[1043503:{Id:1043503 Count:1} 1043491:{Id:1043491 Count:1} 1043459:{Id:1043459 Count:1} 1043475:{Id:1043475 Count:1} 4:{Id:0 Count:0} 8:{Id:0 Count:0} 1043487:{Id:1043487 Count:1} 1:{Id:0 Count:0} 5:{Id:0 Count:0} 9:{Id:0 Count:0} 1043470:{Id:1043470 Count:1} 2:{Id:0 Count:0} 6:{Id:0 Count:0} 1043444:{Id:1043444 Count:1} 1043441:{Id:1043441 Count:1} 1043460:{Id:1043460 Count:1} 3:{Id:0 Count:0} 7:{Id:0 Count:0} 1043464:{Id:1043464 Count:1}]

Have I done something wrong to the 3 functions?

答案1

得分: 4

你正在向Swap(i, j)传递不存在的索引。

映射类型是复合类型。它由两个其他类型定义:键类型和值类型。例如:

map[string]bool

在上面的示例中,string是键类型,bool是值类型。

正如你可能知道的,映射访问返回1个或2个值。在像你这样的1个返回值的上下文中,当给定一个不存在的索引时,映射访问将返回映射值类型的零值。

这意味着如果你在类型为map[string]bool的某个映射m上访问m["im_not_defined"],你将得到一个返回值,它是bool(映射值类型)的零值

你可以通过以下方式检查索引是否定义(在Swap内部):

if a, k := t[uint32(i)]; k {
    t[uint32(j)] = a
} else {
    panic("undefined index")
}

对于j也是类似的。

所以基本上,如果i未定义,GeoNameTally的零值将赋给t[j],这导致你的“空”(零)值。

无论如何,如果你想要对任何东西进行_排序_,你将需要使用切片。映射在定义上是无序的。

英文:

You're passing inexistent indexes to Swap(i, j).

A map type is composite. It is defined in terms of 2 other types: the key type and the value type. Example:

map[string]bool

In the previous example, string is the key type, bool is the value type.

As you may know, map access returns 1 or 2 values. In a 1 return value context like yours, a map access will return the zero-value for the map's value type when given an inexistent index.

This means that if you access m[&quot;im_not_defined&quot;] on some map m of type map[string]bool, you'll get a return value that is the zero-value for bool (the map's value type).

You can check if the indexes are defined by doing (inside Swap):

if a, k := t[uint32(i)]; k {
    t[uint32(j)] = a
} else {
    panic(&quot;undefined index&quot;)
}

And analogously for j.

So basically, if i is undefined, the zero-value of GeoNameTally is assigned to t[j] and that causes your "empty" (zero) values.

Anyhow, if you want to sort anything, you'll have to use a slice. A map is unordered by definition.

答案2

得分: 0

从Go 1.8开始,有一种更简单的方法可以对切片进行排序,而无需定义新类型。你只需创建一个Less(匿名)lambda函数。

a := []int{5, 3, 4, 7, 8, 9}
sort.Slice(a, func(i, j int) bool {
    return a[i] < a[j]
})
for _, v := range a {
    fmt.Println(v)
}
英文:

As of Go 1.8, there is an easier way to sort a slice that does not require you to define new types. You simply create a Less (anonymous) lambda.

a := []int{5, 3, 4, 7, 8, 9}
sort.Slice(a, func(i, j int) bool {
	return a[i] &lt; a[j]
})
for _, v := range a {
	fmt.Println(v)
}

huangapple
  • 本文由 发表于 2015年11月13日 03:52:54
  • 转载请务必保留本文链接:https://go.coder-hub.com/33680134.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定