키로 Go 맵 값 정렬
주제 함수에 의해 반환 된 코드에서 반환 된 맵을 반복 할 때 키가 순서대로 나타나지 않습니다.
키가 순서대로 정렬되고 맵을 정렬하여 키가 순서대로 정렬되고 값이 일치하도록하려면 어떻게해야합니까?
다음은 코드 입니다.
이동 블로그 : 이동 행동에지도는 훌륭한 설명이 있습니다.
범위 루프가있는 맵을 반복 할 때 반복 순서가 지정되지 않으며 한 반복에서 다음 반복까지 동일하다고 보장 할 수 없습니다. Go 1 이후 프로그래머가 이전 구현의 안정적인 반복 순서에 의존 했으므로 런타임은 맵 반복 순서를 무작위로 지정합니다. 안정적인 반복 순서가 필요한 경우 해당 순서를 지정하는 별도의 데이터 구조를 유지해야합니다.
다음은 수정 된 예제 코드 버전입니다. http://play.golang.org/p/dvqcGPYy3-
package main
import (
"fmt"
"sort"
)
func main() {
// To create a map as input
m := make(map[int]string)
m[1] = "a"
m[2] = "c"
m[0] = "b"
// To store the keys in slice in sorted order
var keys []int
for k := range m {
keys = append(keys, k)
}
sort.Ints(keys)
// To perform the opertion you want
for _, k := range keys {
fmt.Println("Key:", k, "Value:", m[k])
}
}
산출:
Key: 0 Value: b
Key: 1 Value: a
Key: 2 Value: c
Go 사양 에 따르면 맵에 대한 반복 순서는 정의되지 않으며 프로그램 실행마다 다를 수 있습니다. 실제로는 정의되지 않았을뿐만 아니라 실제로 의도적으로 무작위 화됩니다. 이는 예전에는 예측이 가능했고 Go 언어 개발자는 사람들이 지정되지 않은 동작에 의존하는 것을 원하지 않았기 때문에 의도적으로 무작위 화하여이 동작에 의존하는 것이 불가능했습니다.
그런 다음해야 할 일은 키를 슬라이스로 가져 와서 정렬 한 다음 다음과 같이 슬라이스에 걸쳐 범위를 지정하는 것입니다.
var m map[keyType]valueType
keys := sliceOfKeys(m) // you'll have to implement this
for _, k := range keys {
v := m[k]
// k is the key and v is the value; do your computation here
}
여기에있는 모든 답변에는 이제 맵의 이전 동작이 포함됩니다. Go 1.12+에서는지도 값을 인쇄하기 만하면 자동으로 키별로 정렬됩니다. 맵 값을 쉽게 테스트 할 수 있기 때문에 추가되었습니다.
func main() {
m := map[int]int{3: 5, 2: 4, 1: 3}
fmt.Println(m)
// In Go 1.12+
// Output: map[1:3 2:4 3:5]
// Before Go 1.12 (the order was undefined)
// map[3:5 2:4 1:3]
}
이제 맵이 테스트를 쉽게하기 위해 키 정렬 순서로 인쇄됩니다. 주문 규칙은 다음과 같습니다.
- 적용 가능한 경우 nil은 낮음을 비교합니다.
- int, float, strings 순서는 <
- NaN은 비 NaN 수레보다 적은 수를 비교합니다.
- bool은 true 전에 false를 비교합니다
- 복잡함은 실제와 가상의 비교
- 컴퓨터 주소로 포인터 비교
- 컴퓨터 주소로 채널 값 비교
- 구조체는 각 필드를 차례로 비교합니다.
- 배열은 각 요소를 차례로 비교합니다.
- 인터페이스 값은 먼저 reflect.Type으로 구체적인 유형을 설명하는 방식으로 비교 한 다음 이전 규칙에서 설명한대로 구체적인 값으로 비교합니다.
지도를 인쇄 할 때 NaN과 같은 비 반사 키 값은 이전에로 표시되었습니다
<nil>. 이 릴리스부터 올바른 값이 인쇄됩니다.
여기에서 자세한 내용을 읽어보십시오 .
저처럼 기본적으로 동일한 정렬 코드를 여러 곳에서 원하거나 코드 복잡성을 낮추고 싶다면 정렬 자체를 별도의 함수로 추상화하여 다음과 같은 함수를 전달할 수 있습니다. 원하는 실제 작업 (물론 각 호출 사이트마다 다를 수 있음).
다음 과 같이 표시된 키 유형 K및 값 유형이 있는 맵 에서 일반적인 정렬 기능은 다음 Go 코드 템플릿과 유사 할 수 있습니다 (Go 버전 1은있는 그대로 지원하지 않음).V<K><V>
/* Go apparently doesn't support/allow 'interface{}' as the value (or
/* key) of a map such that any arbitrary type can be substituted at
/* run time, so several of these nearly-identical functions might be
/* needed for different key/value type combinations. */
func sortedMap<K><T>(m map[<K>]<V>, f func(k <K>, v <V>)) {
var keys []<K>
for k, _ := range m {
keys = append(keys, k)
}
sort.Strings(keys) # or sort.Ints(keys), sort.Sort(...), etc., per <K>
for _, k := range keys {
v := m[k]
f(k, v)
}
}
Then call it with the input map and a function (taking (k <K>, v <V>) as its input arguments) that is called over the map elements in sorted-key order.
So, a version of the code in the answer posted by Mingu might look like:
package main
import (
"fmt"
"sort"
)
func sortedMapIntString(m map[int]string, f func(k int, v string)) {
var keys []int
for k, _ := range m {
keys = append(keys, k)
}
sort.Ints(keys)
for _, k := range keys {
f(k, m[k])
}
}
func main() {
// Create a map for processing
m := make(map[int]string)
m[1] = "a"
m[2] = "c"
m[0] = "b"
sortedMapIntString(m,
func(k int, v string) { fmt.Println("Key:", k, "Value:", v) })
}
The sortedMapIntString() function can be re-used for any map[int]string (assuming the same sort order is desired), keeping each use to just two lines of code.
Downsides include:
- It's harder to read for people unaccustomed to using functions as first-class
- It might be slower (I haven't done performance comparisons)
Other languages have various solutions:
- If the use of
<K>and<V>(to denote types for the key and value) looks a bit familiar, that code template is not terribly unlike C++ templates. - Clojure and other languages support sorted maps as fundamental data types.
- While I don't know of any way Go makes
rangea first-class type such that it could be substituted with a customordered-range(in place ofrangein the original code), I think some other languages provide iterators that are powerful enough to accomplish the same thing.
In reply to James Craig Burley's answer. In order to make a clean and re-usable design, one might choose for a more object oriented approach. This way methods can be safely bound to the types of the specified map. To me this approach feels cleaner and organized.
Example:
package main
import (
"fmt"
"sort"
)
type myIntMap map[int]string
func (m myIntMap) sort() (index []int) {
for k, _ := range m {
index = append(index, k)
}
sort.Ints(index)
return
}
func main() {
m := myIntMap{
1: "one",
11: "eleven",
3: "three",
}
for _, k := range m.sort() {
fmt.Println(m[k])
}
}
Extended playground example with multiple map types.
Important note
In all cases, the map and the sorted slice are decoupled from the moment the for loop over the map range is finished. Meaning that, if the map gets modified after the sorting logic, but before you use it, you can get into trouble. (Not thread / Go routine safe). If there is a change of parallel Map write access, you'll need to use a mutex around the writes and the sorted for loop.
mutex.Lock()
for _, k := range m.sort() {
fmt.Println(m[k])
}
mutex.Unlock()
참고URL : https://stackoverflow.com/questions/23330781/sort-go-map-values-by-keys
'Program Club' 카테고리의 다른 글
| 고정 헤더에 맞게 조정하기 위해 html 앵커 오프셋 (0) | 2020.10.10 |
|---|---|
| MSBuild.exe를 사용하여 cmd 행으로 ASP.NET MVC 4 프로젝트를 "게시" (0) | 2020.10.09 |
| Maven Jacoco 구성-작동하지 않는 보고서에서 클래스 / 패키지 제외 (0) | 2020.10.09 |
| CardView 코너 반경 (0) | 2020.10.09 |
| VBScript — 오류 처리 사용 (0) | 2020.10.09 |