如何在Go语言中按值排序map,并且如果值相等,则按键排序?

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

How to sort map by value and if value equals then by key in Go?

问题

我遇到了一个情况,我想要按值对地图进行排序,如果值相等,则按键排序。这里有一个输入和期望的输出示例。

import "fmt"

func main() {
    wordFrequency := map[string]int{"banana": 3, "america": 2, "abb": 2, "test": 2, "car": 1}
    fmt.Printf("%v", wordFrequency)
}

期望的输出:{"banana": 3, "abb": 2, "america": 2, "test": 2, "car": 1}

在这里,banana排在第一位,因为它的值是3。abbamerica的值都是2,但是abb按升序排序,所以它排在前面。所以我的问题是如何实现这种行为,即首先按值对地图中的条目进行排序,如果值相等,则按键排序。我已经查看了相关文档和以前的问题,但没有直接解决这种情况的。如果由于Go中的地图数据结构而无法实现,我们如何使用其他结构高效地实现呢?

在Python 3中,我们可以按以下方式实现:

d = {'apple':2, 'banana':3, 'almond':2, 'beetroot':3, 'peach':4}
[k for k, v in sorted(d.items(), key=lambda item: (-item[1], item[0]))]

这是Python的等效问题的链接:链接

注意:这个问题问如何按值对地图进行排序。我的问题是特定于按值排序,然后按键排序(如果值相等)。

英文:

I came across a situation where I want to sort a map first by value and if the values are equal then by key in GO. Here is an example of input and expected output.

import "fmt"

func main() {
     wordFrequency := map[string]int{"banana": 3, "america": 2, "abb": 2, "test": 2, "car": 1}
     fmt.Printf("%v", wordFrequency)
}

Expected output : {"banana": 3,"abb": 2, "america": 2, "test": 2, "car": 1}

Here banana is at first because its value is 3. abb and america both value is 2 but abb comes first as sorted in ascender order. So my question is how to implement this behaviour where we sort the entries in map first by value and if value equals we sort them by key. I have checked related documentation and previous questions but none directly address this scenario. If it is not possible to do due to map data structure in Go, how can we do that efficiently with other structures?

In Python 3, we can do this in the following way

>>> d = {'apple':2, 'banana':3, 'almond':2, 'beetroot':3, 'peach':4}
>>> [k for k, v in sorted(d.iteritems(), key=lambda(k, v): (-v, k))]
['peach', 'banana', 'beetroot', 'almond', 'apple']

Here is a link for the equivalent question for Python link

N.B: This question asks how to sort map by value. My question is specific to sort by value and then key (if value equals).

答案1

得分: 2

你无法对 map 进行排序。

  1. map 转换为键值对结构体的切片。
  2. 对切片进行排序(参见如何对具有多个排序参数的结构体进行排序?

例如:

func main() {
    wordFrequency := map[string]int{"banana": 3, "america": 2, "abb": 2, "test": 2, "car": 1}

    vec := mapToSlice(wordFrequency)

    sort.Slice(vec, func(i, j int) bool {
        // 1. 值不同 - 按值排序(逆序)
        if vec[i].value != vec[j].value {
            return vec[i].value > vec[j].value
        }
        // 2. 只有值相同时 - 按键排序
        return vec[i].key < vec[j].key
    })

    fmt.Printf("%v", vec)
}

func mapToSlice(in map[string]int) []KV {
    vec := make([]KV, len(in))
    i := 0
    for k, v := range in {
        vec[i].key = k
        vec[i].value = v
        i++
    }
    return vec
}

type KV struct {
    key   string
    value int
}

输出结果为:

[{banana 3} {abb 2} {america 2} {test 2} {car 1}]

在线演示

英文:

You can't sort a map.

  1. Convert the map to a slice of key-value-pair structs.
  2. Sort the slice (see also How to sort struct with multiple sort parameters?)

For example like this:

func main() {
	wordFrequency := map[string]int{&quot;banana&quot;: 3, &quot;america&quot;: 2, &quot;abb&quot;: 2, &quot;test&quot;: 2, &quot;car&quot;: 1}

	vec := mapToSlice(wordFrequency)

	sort.Slice(vec, func(i, j int) bool {
        // 1. value is different - sort by value (in reverse order)
		if vec[i].value != vec[j].value {
			return vec[i].value &gt; vec[j].value
		}
        // 2. only when value is the same - sort by key
		return vec[i].key &lt; vec[j].key
	})

	fmt.Printf(&quot;%v&quot;, vec)
}

func mapToSlice(in map[string]int) []KV {
	vec := make([]KV, len(in))
	i := 0
	for k, v := range in {
		vec[i].key = k
		vec[i].value = v
		i++
	}
	return vec
}

type KV struct {
	key   string
	value int
}

Prints:

[{banana 3} {abb 2} {america 2} {test 2} {car 1}]

Live demo

huangapple
  • 本文由 发表于 2021年11月29日 15:30:09
  • 转载请务必保留本文链接:https://go.coder-hub.com/70151032.html
匿名

发表评论

匿名网友

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

确定