简体   繁体   English

如何从Golang的地图中提取x top int值?

[英]How to extract x top int values from a map in Golang?

I have a map[string]int 我有一张map[string]int

I want to get the x top values from it and store them in another data structure, another map or a slice. 我想从中获取x顶部值并将它们存储在另一个数据结构,另一个映射或切片中。 From https://blog.golang.org/go-maps-in-action#TOC_7. 来自https://blog.golang.org/go-maps-in-action#TOC_7。 I understood that: 我明白:

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. 当使用范围循环在地图上进行迭代时,未指定迭代顺序,并且不能保证每次迭代之间都相同。

so the result structure will be a slice then. 因此,结果结构将是一个切片。

I had a look at several related topics but none fits my problem: 我看了几个相关主题,但没有一个适合我的问题:

related topic 1 相关主题1

related topic 2 相关主题2

related topic 3 相关主题3

What would be the most efficient way to do this please? 请问最有效的方法是什么?

Thanks, 谢谢,

Edit: My solution would be to turn my map into a slice and sort it, then extract the first x values. 编辑:我的解决方案是将地图变成一个切片并对其进行排序,然后提取第一个x值。
But is there a better way ? 但是有更好的方法吗?

package main

import (
    "fmt"
    "sort"
)

func main() {

    // I want the x top values
    x := 3

    // Here is the map
    m := make(map[string]int)
    m["k1"] = 7
    m["k2"] = 31
    m["k3"] = 24
    m["k4"] = 13
    m["k5"] = 31
    m["k6"] = 12
    m["k7"] = 25
    m["k8"] = -8
    m["k9"] = -76
    m["k10"] = 22
    m["k11"] = 76

    // Turning the map into this structure
    type kv struct {
        Key   string
        Value int
    }

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

    // Then sorting the slice by value, higher first.
    sort.Slice(ss, func(i, j int) bool {
        return ss[i].Value > ss[j].Value
    })

    // Print the x top values
    for _, kv := range ss[:x] {
        fmt.Printf("%s, %d\n", kv.Key, kv.Value)
    }
}

Link to golang playground example 链接到Golang游乐场示例

If I want to have a map at the end with the x top values, then with my solution I would have to turn the slice into a map again. 如果我想在地图的末尾有x个top值,那么根据我的解决方案,我将不得不再次将切片变成地图。 Would this still be the most efficient way to do it? 这仍然是最有效的方法吗?

Creating a slice and sorting is a fine solution; 创建切片和排序是一个很好的解决方案; however, you could also use a heap . 但是,您也可以使用 The Big O performance should be equal for both implementations (n log n) so this is a viable alternative with the advantage that if you want to add new entries you can still efficiently access the top N items without repeatedly sorting the entire set. 两种实现方式的Big O性能应相等(n log n),因此这是一个可行的选择,其优点是,如果要添加新条目,您仍可以有效地访问前N个项目,而无需重复排序整个集合。

To use a heap, you would implement the heap.Interface for the kv type with a Less function that compares Values as greater than ( h[i].Value > h[j].Value ), add all of the entries from the map, and then pop the number of items you want to use. 要使用堆,您可以使用一个Less函数(将Values 大于h[i].Value > h[j].Value )进行比较)来实现kv类型的heap.Interface ,添加映射中的所有条目,然后弹出要使用的项目数。

For example ( Go Playground ): 例如( Go Playground ):

func main() {
  m := getMap()

  // Create a heap from the map and print the top N values.
  h := getHeap(m)
  for i := 1; i <= 3; i++ {
    fmt.Printf("%d) %#v\n", i, heap.Pop(h))
  }
  // 1) main.kv{Key:"k11", Value:76}
  // 2) main.kv{Key:"k2", Value:31}
  // 3) main.kv{Key:"k5", Value:31}
}

func getHeap(m map[string]int) *KVHeap {
  h := &KVHeap{}
  heap.Init(h)
  for k, v := range m {
    heap.Push(h, kv{k, v})
  }
  return h
}

// See https://golang.org/pkg/container/heap/
type KVHeap []kv

// Note that "Less" is greater-than here so we can pop *larger* items.
func (h KVHeap) Less(i, j int) bool { return h[i].Value > h[j].Value }
func (h KVHeap) Swap(i, j int)      { h[i], h[j] = h[j], h[i] }
func (h KVHeap) Len() int           { return len(h) }

func (h *KVHeap) Push(x interface{}) {
  *h = append(*h, x.(kv))
}

func (h *KVHeap) Pop() interface{} {
  old := *h
  n := len(old)
  x := old[n-1]
  *h = old[0 : n-1]
  return x
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM