Làm thế nào để sắp xếp một Map [string] int theo các giá trị của nó?


81

Đưa ra khối mã này

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

Tôi muốn in ra

foo, 20
bar, 20
hello, 10

Theo thứ tự từ cao nhất đến thấp nhất

Cảm ơn!

Câu trả lời:


92

Tìm thấy câu trả lời trên Golang-nut bởi Andrew Gerrand

Bạn có thể cài đặt giao diện sắp xếp bằng cách viết hàm 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] }

Đối với bài đăng gốc, vui lòng tìm ở đây https://groups.google.com/forum/#!topic/golang-nuts/FT7cjmcL7gw


1
... ngoại trừ việc Lesstrả về kết quả sai. Để sắp xếp ngược lại, hãy sử dụng >.
Fred Foo

3
@larsmans Tôi xấu! Cảm ơn đã chỉ ra điều đó. Tôi đã thay sử dụng sort.Reverse để có được kết quả ngược lại
samol

2
Thậm chí tốt hơn, tôi thậm chí không biết về sort.Reverse. +1.
Fred Foo

71

Có một hàm sort.Slice mới trong go 1.8, vì vậy bây giờ việc này đơn giản hơn.

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


Tôi không thích cách đầu ra không phải là bản đồ mà tôi đã bắt đầu
hendry

@hendry câu trả lời này đặc biệt phản ứng với định dạng trong câu hỏi gốc. Trong go1.12, bạn chỉ có thể in bản đồ và nó sẽ được sắp xếp, hãy xem vấn đề: github.com/golang/go/issues/21095
voutasaurus

gần như hoàn hảo, tôi đề nghị xử lý các phần tử có cùng giá trị.
Tommaso Barbugli

@TommasoBarbugli như thế nào? Làm cho chúng ổn định? Hay sắp xếp theo thứ tự bảng chữ cái? Sự ổn định khá chắc chắn là không thể bởi vì Go ngẫu nhiên hóa thứ tự lặp lại bản đồ đặc biệt để ngăn bạn dựa vào một thứ tự được gọi rõ ràng là không quan trọng đối với trình biên dịch. Đối với thứ tự bảng chữ cái, bạn có thể dễ dàng sửa đổi hàm ẩn danh được chuyển sang sắp xếp
Voutasaurus

1
Ngoài ra còn có một sắp xếp.SliceStable (cũng được thêm trong Go 1.8) giữ nguyên thứ tự ban đầu của các phần tử bằng nhau.
Dave Yarwood

16

Ví dụ:

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)
                }
        }
}

Sân chơi


Đầu ra:

foo, 20
bar, 20
hello, 10

@DarshanComputing: Cảm ơn, đã sửa.
zzzz

1
Điều này giả định rằng các giá trị không có danh tính.
newacct

2
@newacct: Nó giải quyết duy nhất vấn đề OP, không phải là trường hợp chung ;-)
zzzz

giải pháp này cũng phù hợp với trường hợp của tôi, dễ hiểu.
Tommy,

1

Tôi thường cần sắp xếp một map[string]intsố thứ mà tôi đang đếm và đã sử dụng như sau.

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
}

Sử dụng nó để lặp lại các phím theo thứ tự giá trị

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

Trong trường hợp của tôi, tôi đang xử lý một chương trình mà tôi đã tạo. Trong chương trình này, tôi đã tạo một Bản đồ giống như bạn, với stringint. Sau đó, tôi phát hiện ra như bạn rằng Go không thực sự có một cách tích hợp để sắp xếp một cái gì đó như thế này. Tôi đã đọc các câu trả lời khác và không thực sự thích những gì tôi đọc.

Vì vậy, tôi đã cố gắng nghĩ về vấn đề theo cách khác. Go có thể sử dụng sort.Ints với một lát cắt. Ngoài ra, Go có thể sử dụng sort.Slice với một bộ so sánh tùy chỉnh. Vì vậy, thay vì tạo Bản đồ của stringint, tôi đã tạo structcủa stringint. Sau đó, bạn có thể sắp xếp:

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)
}

Điều này sẽ không hiệu quả với tất cả mọi người, vì có thể bạn sẽ buộc phải xử lý bản đồ do người khác tạo ra. Nhưng nó rất hữu ích cho tôi. Phần tốt là, không giống như tất cả các câu trả lời khác, câu trả lời này không sử dụng vòng lặp.


-1

Trước tiên hãy sắp xếp các khóa theo giá trị và sau đó lặp lại bản đồ:

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
Tôi chắc chắn rằng những người đang phản đối, có thể là những người không đọc kỹ hàm so sánh. Câu trả lời cũng được chấp nhận không tạo ra bản in mà OP yêu cầu mà thay vào đó giới thiệu cấu trúc dữ liệu mới phải được duy trì trong mã thực. Dưới đây là liên kết sân chơi cho câu trả lời của tôi play.golang.org/p/Y4lrEm2-hT5
AlexanderYastrebov
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.