Map [string] int를 값으로 정렬하는 방법은 무엇입니까?


81

이 코드 블록이 주어지면

map[string]int {"hello":10, "foo":20, "bar":20}

인쇄하고 싶습니다

foo, 20
bar, 20
hello, 10

높은 순으로

감사!

답변:


92

Andrew Gerrand의 Golang-nuts에서 답을 찾았습니다.

len / less / swap 함수를 작성하여 정렬 인터페이스를 구현할 수 있습니다.

func rankByWordCount(wordFrequencies map[string]int) PairList{
  pl := make(PairList, len(wordFrequencies))
  i := 0
  for k, v := range wordFrequencies {
    pl[i] = Pair{k, v}
    i++
  }
  sort.Sort(sort.Reverse(pl))
  return pl
}

type Pair struct {
  Key string
  Value int
}

type PairList []Pair

func (p PairList) Len() int { return len(p) }
func (p PairList) Less(i, j int) bool { return p[i].Value < p[j].Value }
func (p PairList) Swap(i, j int){ p[i], p[j] = p[j], p[i] }

원본 게시물은 여기에서 찾으십시오. https://groups.google.com/forum/#!topic/golang-nuts/FT7cjmcL7gw


1
... Less잘못된 결과를 반환하는 것을 제외하고 는. 역 정렬의 경우 >.
Fred Foo

3
@larsmans 내 나쁜! 지적 해 주셔서 감사합니다. 대신 sort.Reverse를 사용하여 역 결과를 얻었습니다
samol

2
더 좋은 점은에 대해 몰랐습니다 sort.Reverse. +1.
Fred Foo

72

go 1.8에 새로운 sort.Slice 함수가 있으므로 이제 더 간단합니다.

package main

import (
    "fmt"
    "sort"
)

func main() {
    m := map[string]int{
        "something": 10,
        "yo":        20,
        "blah":      20,
    }

    type kv struct {
        Key   string
        Value int
    }

    var ss []kv
    for k, v := range m {
        ss = append(ss, kv{k, v})
    }

    sort.Slice(ss, func(i, j int) bool {
        return ss[i].Value > ss[j].Value
    })

    for _, kv := range ss {
        fmt.Printf("%s, %d\n", kv.Key, kv.Value)
    }
}

https://play.golang.org/p/y1_WBENH4N


I 출력이 내가 함께 시작한지도하지 얼마나 싫어
헨 드리

@hendry이 답변은 특히 원래 질문의 형식에 대한 응답입니다. : go1.12에서 문제를보고, 당신은 단지지도를 인쇄 할 수 있으며 정렬됩니다 github.com/golang/go/issues/21095
voutasaurus

거의 완벽합니다. 동일한 값을 가진 요소를 처리하는 것이 좋습니다.
Tommaso Barbugli

@TommasoBarbugli 어떻게? 안정적으로 만드시겠습니까? 아니면 알파벳순으로 정렬 하시겠습니까? Go는 특히 컴파일러에 중요하지 않은 것으로 명시 적으로 호출 된 순서에 의존하는 것을 막기 위해 맵 반복 순서를 무작위 화하므로 안정성이 불가능합니다. 알파벳순으로 정렬하기 위해 전달 된 익명 함수를 쉽게 수정할 수 있습니다 .Slice
voutasaurus

1
동일한 요소의 원래 순서를 유지 하는 sort.SliceStable (Go 1.8에도 추가됨)도 있습니다.
Dave Yarwood

16

예를 들면 :

package main

import (
        "fmt"
        "sort"
)

func main() {
        m := map[string]int{"hello": 10, "foo": 20, "bar": 20}
        n := map[int][]string{}
        var a []int
        for k, v := range m {
                n[v] = append(n[v], k)
        }
        for k := range n {
                a = append(a, k)
        }
        sort.Sort(sort.Reverse(sort.IntSlice(a)))
        for _, k := range a {
                for _, s := range n[k] {
                        fmt.Printf("%s, %d\n", s, k)
                }
        }
}

운동장


산출:

foo, 20
bar, 20
hello, 10

@DarshanComputing : 감사합니다.
zzzz

1
이것은 값에 ID가 없다고 가정합니다.
newacct 2013 년

2
@newacct : 그것은 ;-) 일반적인 경우에만 OP 문제가 아닌 해결
ZZZZ

이 솔루션은 제 경우에도 효과가 있었고 이해하기 쉽습니다.
Tommy

1

나는 종종 map[string]int내가 세고있는 것을 분류해야 하고 다음을 사용하고있다.

func rankMapStringInt(values map[string]int) []string {
    type kv struct {
        Key   string
        Value int
    }
    var ss []kv
    for k, v := range values {
        ss = append(ss, kv{k, v})
    }
    sort.Slice(ss, func(i, j int) bool {
        return ss[i].Value > ss[j].Value
    })
    ranked := make([]string, len(values))
    for i, kv := range ss {
        ranked[i] = kv.Key
    }
    return ranked
}

값 순서대로 키를 반복하는 데 사용합니다.

values := map[string]int{"foo": 10, "bar": 20, "baz": 1}

for i, index := range rankMapStringInt(values) {
    fmt.Printf("%3d: %s -> %d", i, index, values[index])
}

0

제 경우에는 제가 만든 프로그램을 다루고있었습니다. 이 프로그램에서는, 나는 당신처럼지도를 만들어와 stringint. 그런 다음 Go에는 이와 같은 것을 정렬 할 수있는 기본 제공 방법이 없다는 것을 여러분처럼 알게되었습니다. 나는 다른 답변을 읽었고 내가 읽은 것을 정말 좋아하지 않았습니다.

그래서 저는 문제에 대해 다르게 생각하려고했습니다. Go는 슬라이스와 함께 sort.Ints 를 사용할 수 있습니다 . 또한 Go는 사용자 정의 비교기와 함께 sort.Slice 를 사용할 수 있습니다 . 그래서 대신지도를 작성 string하고 int, 나는 창조 structstringint. 그런 다음 정렬 할 수 있습니다.

package main

import (
   "fmt"
   "sort"
)

type File struct {
   Name string
   Size int
}

func main() {
   a := []File{{"april.txt", 9}, {"may.txt", 7}}
   f := func (n, n1 int) bool {
      return a[n].Size < a[n1].Size
   }
   sort.Slice(a, f)
   fmt.Println(a)
}

다른 사람이 만든지도를 다루어야 할 수도 있으므로 모든 사람에게 적용되지는 않습니다. 그러나 그것은 나에게 유용했습니다. 좋은 부분은 다른 모든 답변과 달리 루프를 사용하지 않는다는 것입니다.


-1

먼저 값으로 키를 정렬 한 다음 맵을 반복합니다.

package main

import (
    "fmt"
    "sort"
)

func main() {
    counts := map[string]int{"hello": 10, "foo": 20, "bar": 20}

    keys := make([]string, 0, len(counts))
    for key := range counts {
        keys = append(keys, key)
    }
    sort.Slice(keys, func(i, j int) bool { return counts[keys[i]] > counts[keys[j]] })

    for _, key := range keys {
        fmt.Printf("%s, %d\n", key, counts[key])
    }
}

1
나는 누가 반대표를 던지고 있는지, 아마도 비교기 기능을주의 깊게 읽지 않는 사람들을 확신합니다. 또한 받아 들여지는 대답은 요청한 출력물을 생성하지 않지만 대신 실제 코드로 유지 해야하는 새로운 데이터 구조를 도입합니다. 내 대답 play.golang.org/p/Y4lrEm2-hT5
AlexanderYastrebov에
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.