如何在Go中根据另一个map的键值对对map进行排序?

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

How do I sort a map in Go based on another map's key values?

问题

我需要根据另一个映射的键对映射进行排序,因为我当前的函数返回的映射是无序的,所以我希望它能根据这个名称的顺序保持一致,就像在reference中看到的那样。我知道一些排序函数,但是在实现它们时遇到了一些问题。再次强调,我需要根据reference变量的顺序对名称进行排序,而不是按字母顺序排序,只是基于一个特定的映射顺序。如果有人能帮忙解决这个问题就太好了。

为了澄清,我需要根据与reference变量中的顺序相同的顺序对testMap()和testMap2()返回的值进行排序。reference变量显示了两个名称之间的关联(命名约定的差异)。

package main

import (
	"fmt"
)

var reference = map[string]string{"Ali": "Ali_1", "Cat": "Cat1", "Bob": "Bob"}

func main() {
    testMap() 
}

func testMap() map[string]int {
    return map[string]int{"Ali_1": 2, "Bob": 3, "Cat1": 3} // 目标是按照与reference变量中的键(名称)相同的顺序对其进行排序
}

func testMap2() map[string]int {
    return map[string]int{"Ali": 2, "Bob": 3, "Cat": 3} // 目标是按照与reference变量中的键(名称)相同的顺序对其进行排序
}
英文:

I need to sort a map based on the keys of another map because my current function that returns a map is not sorted so I need it to be consistent based on this order of names, as seen in reference. I am aware of some of the sort functions, however, I am having some trouble implementing them. To reiterate, I need the names to be sorted the same way as the reference variable; no alphabetical order just based on one specific map ordering. It would be great if someone could please help with this.

To clarify, I need to sort the returned values from testMap() and testMap2() based on the same order as reference. The reference variable shows the connection between the two names (the difference in naming conventions).

package main

import (
	"fmt"
)

var reference = map[string]string{"Ali": "Ali_1", "Cat": "Cat1", "Bob": "Bob"}

func main() {
    testMap() 
}

func testMap() map[string]int {
    return map[string]int{"Ali_1": 2, "Bob": 3, "Cat1": 3} // goal is to sort this in the same order of keys(names) as the reference variable
}

func testMap2() map[string]int {
    return map[string]int{"Ali": 2, "Bob": 3, "Cat": 3} // goal is to sort this in the same order of keys(names) as the reference variable
}

答案1

得分: 2

预备说明

重申一些重要的内容:Go语言中的映射(maps)没有定义的顺序,因此无法对它们进行排序或保证它们的顺序。

来自Go maps in action的内容:

> 当使用range循环迭代映射时,迭代顺序没有指定,并且不能保证从一次迭代到下一次迭代的顺序相同。如果您需要稳定的迭代顺序,必须维护一个单独的数据结构来指定该顺序。


回答

您可以遍历reference中的键/值,并使用第一个和第二个键从第一个和第二个映射中获取值。

package main

import (
	"fmt"
)

var reference = map[string]string{"Ali": "Ali_1", "Cat": "Cat1", "Bob": "Bob"}

func main() {
	m1 := testMap()
	m2 := testMap2()

	for key1, key2 := range reference {
		v1, _ := m1[key1]
		v2, _ := m2[key2]
		fmt.Printf("%s/%s: (%d, %d)\n", key1, key2, v1, v2)
        // 不确定您对这些值的要求,所以我只是打印出来了
	}
}

func testMap() map[string]int {
	return map[string]int{"Ali_1": 2, "Bob": 3, "Cat1": 3} // 目标是按照与reference变量相同的键(名称)顺序对其进行排序
}

func testMap2() map[string]int {
	return map[string]int{"Ali": 2, "Bob": 3, "Cat": 3} // 目标是按照与reference变量相同的键(名称)顺序对其进行排序
}

请注意,这仍然不能保证顺序,只能将“匹配”的键的值配对。

如果您想要顺序,您需要使用具有顺序的数据结构(例如切片)。例如:

package main

import (
	"fmt"
)

var keyOrder = []string{"Ali", "Cat", "Bob"}
var reference = map[string]string{"Ali": "Ali_1", "Cat": "Cat1", "Bob": "Bob"}

func main() {
	m1 := testMap()
	m2 := testMap2()

	for _, key1 := range keyOrder {
		key2, _ := reference[key1]
		v1, _ := m1[key1]
		v2, _ := m2[key2]
		fmt.Printf("%s/%s: (%d, %d)\n", key1, key2, v1, v2)
	}
}

func testMap() map[string]int {
	return map[string]int{"Ali_1": 2, "Bob": 3, "Cat1": 3} // 目标是按照与reference变量相同的键(名称)顺序对其进行排序
}

func testMap2() map[string]int {
	return map[string]int{"Ali": 2, "Bob": 3, "Cat": 3} // 目标是按照与reference变量相同的键(名称)顺序对其进行排序
}

或者您可以将reference更改为类似以下的形式:

var reference = [][]string{{"Ali", "Ali_1"}, {"Cat", "Cat1"}, {"Bob", "Bob"}}

(如果涉及到多个映射,这种方式更灵活,但必须确保子切片中的顺序与映射的顺序相匹配。)

随着我们的进展,这种方法变得越来越混乱。您可能考虑完全不同的方法,例如使用更复杂的类型(如结构体)或者退一步考虑为什么首先会出现这些不匹配的键。

英文:

Preliminary note

To reiterate something important from the comments: maps in Go do not have defined orders and you therefore cannot sort them or guarantee their order.

From Go maps in action:

> When iterating over a map with a range loop, the iteration order is not specified and is not guaranteed to be the same from one iteration to the next. If you require a stable iteration order you must maintain a separate data structure that specifies that order.


Answer

You can iterate over the keys/values in reference and get the value from the first and second map using the first and second key.

package main

import (
	"fmt"
)

var reference = map[string]string{"Ali": "Ali_1", "Cat": "Cat1", "Bob": "Bob"}

func main() {
	m1 := testMap()
	m2 := testMap2()

	for key1, key2 := range reference {
		v1, _ := m1[key1]
		v2, _ := m2[key2]
		fmt.Printf("%s/%s: (%d, %d)\n", key1, key2, v1, v2)
        // not sure what you want with these, so I'm just printing
	}
}

func testMap() map[string]int {
	return map[string]int{"Ali_1": 2, "Bob": 3, "Cat1": 3} // goal is to sort this in the same order of keys(names) as the reference variable
}

func testMap2() map[string]int {
	return map[string]int{"Ali": 2, "Bob": 3, "Cat": 3} // goal is to sort this in the same order of keys(names) as the reference variable
}

Note that this still does not guarantee order, only that the values for the "matching" keys are paired up.

If you want order you'll need something that has order (e.g. a slice). For example:

package main

import (
	"fmt"
)

var keyOrder = []string{"Ali", "Cat", "Bob"}
var reference = map[string]string{"Ali": "Ali_1", "Cat": "Cat1", "Bob": "Bob"}

func main() {
	m1 := testMap()
	m2 := testMap2()

	for _, key1 := range keyOrder {
		key2, _ := reference[key1]
		v1, _ := m1[key1]
		v2, _ := m2[key2]
		fmt.Printf("%s/%s: (%d, %d)\n", key1, key2, v1, v2)
	}
}

func testMap() map[string]int {
	return map[string]int{"Ali_1": 2, "Bob": 3, "Cat1": 3} // goal is to sort this in the same order of keys(names) as the reference variable
}

func testMap2() map[string]int {
	return map[string]int{"Ali": 2, "Bob": 3, "Cat": 3} // goal is to sort this in the same order of keys(names) as the reference variable
}

or you can change reference to look something like this:

var reference = [][]string{{"Ali", "Ali_1"}, {"Cat", "Cat1"}, {"Bob", "Bob"}}

(Which would be more flexible if you have more than two maps involved, but you have to make sure the order in the subslices matches the map order.)

Though this is getting more hacked together as we progress. You might consider a different approach altogether, maybe using more complex types like structs or something. Or take a step back and consider why you have these mismatched keys in the first place.

答案2

得分: 0

所有的答案和示例在网络上,由于某种“未知”的原因,在迭代键时停止了,这些键在单独的循环中被排序并且只是用fmt.Print打印出来,但是如果你尝试重新创建一个映射并按排序后的键存储数据,你将会得到一个非排序的映射。因为Go语言可能不支持按设计排序。如果有人能创建一个反驳这一可能性的示例,那将是很棒的。

英文:

All answers and examples in web, for some "unknown" reason, has been stopped on iteration keys got sorted in separate for and just printing them with fmt.Print, but if you will try to recreate map and to store your data by keys sorted, again, you will get non sorted map. Because GoLang doesn't support sorting by design probably. Will be amazing if somebody will create an example which refutes that it is possible.

huangapple
  • 本文由 发表于 2021年7月2日 07:41:39
  • 转载请务必保留本文链接:https://go.coder-hub.com/68218027.html
匿名

发表评论

匿名网友

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

确定