Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
I would likde to sort this map by cost
type Graph struct {
vertice string
cost float64
}
var graph map[string][]Graph
In the order of lowest to highest
Thanks!
If the goal is to sort each slice in graph by cost, you only need to implement sort.Interface on []Graph, then use a for loop to loop through the values.
type ByCost []Graph
func (gs *ByCost) Len() int { return len(gs) }
func (gs *ByCost) Less(i, j int) bool { return gs[i].cost < gs[j].cost }
func (gs *ByCost) Swap(i, j int) { gs[i], gs[j] = gs[j], gs[i] }
for _, v := range graph {
sort.Sort(ByCost(v))
If you're trying to iterate through the map in sorted order by the sum of the costs in the []Graph, that's going to be much less clean.
type GraphKeyPairs struct {
key string
value []Graph
}
// Build a slice to store our map values
sortedGraph := make([]GraphKeyPairs, 0, len(graph))
for k,v := range graph {
// O(n)
gkp := GraphKeyPairs{key: k, value: v}
sortedGraph = append(sortedGraph, gkp)
}
type BySummedCost []GraphKeyPairs
func (gkp *BySummedCost) Len() int { return len(gkp) }
func (gkp *BySummedCost) Swap(i, j int) { gkp[i], gkp[j] = gkp[j], gkp[i] }
func (gkp *BySummedCost) Less(i, j int) bool {
// O(2n)
iCost, jCost := 0, 0
for _, v := range gkp[i].value {
iCost += v.cost
}
for _, v := range gkp[j].value {
jCost += v.cost
}
return iCost < jCost
}
sort.Sort(BySummedCost(sortedGraph))
Related
This question already has answers here:
Go composite literal for type of primitive value
(1 answer)
Go: cast slice of primitive to a slice of its alias [duplicate]
(1 answer)
Closed 9 months ago.
type ByHeight []golfTree
type ByAge []Person
func (a ByAge) Len() int { return len(a) }
func (a ByAge) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a ByAge) Less(i, j int) bool { return a[i].Age < a[j].Age }
func (a ByHeight) Len() int { return len(a) }
func (s ByHeight) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (s ByHeight) Less(i, j int) bool { return s[i].height < s[j].height }
func test() {
p := make([]Person, 10, 10)
sort.Sort(ByAge(p))
f := make([]golfTree, 10, 10)
***sort.Sort(ByHeight{f})***
}
Here is the code that sort for two slice, but the ByHeight sort always raise an error. It says that
Cannot use 'f' (type []golfTree) as the type golfTree
But for person and tree, I nearly do the same thing. What's the error ?
Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 4 years ago.
Improve this question
I am trying to sort a (Golang) slice of structs by one of their fields.
I have looked at a lot of examples and go-playgrounds and the documentation, and I feel like I get it, but I still can't get my code to work quite right.
package main
import (
"fmt"
"sort"
)
type Method struct {
MethodNumber int `json:"methodNumber"`
MethodRank int `json:"rank"`
MethodRMSE float64 `json:"error"`
Forecast []float64 `json:"forecast"`
}
// extra stuff for sorting.
type ByError []Method
func (s ByError) Len() int {
return len(s)
}
func (s ByError) Swap(i, j int) {
s[i], s[j] = s[j], s[i]
}
func (s ByError) Less(i, j int) bool {
return s[i].MethodRMSE < s[i].MethodRMSE
}
func main() {
xs := make([]Method, 0)
fmt.Println(len(xs))
xs = append(xs, Method{MethodNumber: 1, MethodRMSE: 10})
xs = append(xs, Method{MethodNumber: 2, MethodRMSE: 8})
xs = append(xs, Method{MethodNumber: 3, MethodRMSE: 6})
xs = append(xs, Method{MethodNumber: 4, MethodRMSE: 4})
fmt.Printf("%+v \n", xs)
sort.Sort(ByError(xs))
fmt.Printf("%+v \n", xs)
sort.Sort(sort.Reverse(ByError(xs)))
fmt.Printf("%+v \n", xs)
}
My Non-Working Code : https://play.golang.org/p/h8SHVjTQSPM
A Working Near-Duplicate : https://play.golang.org/p/vActL0VwK3L (from another SO user)
Mine should be sorting by RMSE, but it doesn't change the order at all. Right now, the result of my go playground should be having it sort by RMSE ascending, then sort in reverse.
typo here
func (s ByError) Less(i, j int) bool {
return s[i].MethodRMSE < s[i].MethodRMSE
}
should be
func (s ByError) Less(i, j int) bool {
return s[i].MethodRMSE < s[j].MethodRMSE
}
Because it's a little hard to see, the first (wrong) version compares the item to itself (both indexes are i). The second properly uses both i and j.
I have a 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.
From 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
related topic 2
related topic 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.
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
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. 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.
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.
For example (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
}
I'm trying to figure out the best way to recursively go through a [string]int map in Go. I'm building a game in which multiple countries are involved, and grouped together by teams of two in the end.
The goal is to match the first two countries with the lowest 'score' into its own group of two, and add it back to the collection giving the new map a total value of the scores of those countries.
Then recursively doing that to all the groups, ending up with one group and one total value in the end.
For example, if you had:
score := map[string]int{
"Canada": 7,
"US": 2,
"Germany": 3,
"Korea": 4,
}
group1 = {[US:2] [Germany:3]} with a total of 5
group1 would now be put back into the initial collection with a 'score' of 5 since it takes the two lowest scores. We would now have:
score := map[string]int{
"Canada": 7,
"Korea": 4,
group1: `US:2 Germany:3` with a total of 5
}
If this was now the lowest score in the collection, the next iteration would be:
group2 = {[Korea:4] [group1:5]}
score := map[string]int{
"Canada": 7,
group2: `Korea:4 group1:5` with a total of 9
}
And so on until you're left with one.. I think the basic structure should be something like this. However, I'm unsure of the proper way to do this since the data structure is now encompassing a [string]int map, as well as this new map.
I realize this is not such a generic question, but could an interface be used for this? I'm very new to Go, so advice would be helpful.
Here is an example to further illustrate what I mean:
https://play.golang.org/p/cnkTc0HBY4
Your problem can "easy" be solved using a heap data structure.
package main
import (
"container/heap"
"fmt"
)
// Something that has a score
type Scoreable interface {
fmt.Stringer
Score() int
}
// A country has a name and a score
type Country struct {
name string
score int
}
// Country implements Scoreable
func (c Country) Score() int {
return c.score
}
// ... and fmt.Stringer
func (c Country) String() string {
return fmt.Sprintf("%s [%d]", c.name, c.score)
}
// A team consists of two Scoreable's and has itself a score
type Team struct {
team1, team2 Scoreable
score int
}
// Team implements Scoreable
func (t Team) Score() int {
return t.score
}
// ... and fmt.Stringer
func (t Team) String() string {
return fmt.Sprintf("(%s + %s)", t.team1.String(), t.team2.String())
}
// The heap will be implemented using a slice of Scoreables
type TeamHeap []Scoreable
// TeamHeap implements heap.Interface
func (th TeamHeap) Len() int {
return len(th)
}
func (th TeamHeap) Less(i, j int) bool {
return th[i].Score() < th[j].Score()
}
func (th TeamHeap) Swap(i, j int) {
th[i], th[j] = th[j], th[i]
}
func (th *TeamHeap) Push(t interface{}) {
*th = append(*th, t.(Scoreable))
}
func (th *TeamHeap) Pop() interface{} {
old := *th
n := len(old)
t := old[n-1]
*th = old[0 : n-1]
return t
}
// The main function
func main() {
// Create a heap and initialize it
teams := &TeamHeap{}
heap.Init(teams)
// Push the countries (NB: heap.Push(), not teams.Push())
heap.Push(teams, Country{"Canada", 7})
heap.Push(teams, Country{"US", 2})
heap.Push(teams, Country{"Germany", 3})
heap.Push(teams, Country{"Korea", 4})
// Take the two teams with lowest score and make a new team of them
// Repeat this until there's only one team left
for teams.Len() > 1 {
t1 := heap.Pop(teams).(Scoreable)
t2 := heap.Pop(teams).(Scoreable)
heap.Push(teams, Team{t1, t2, t1.Score() + t2.Score()})
}
// Print the teams that we now have in the heap
for teams.Len() > 0 {
t := heap.Pop(teams).(Team)
fmt.Println(t)
}
}
You can find runnable code on the Go Playground.
package main
import (
"container/heap"
"fmt"
)
//Recursive data structure may looks something like
type Group struct {
Score int
Left *Group
Right *Group
Country string
}
//You can use slice to hold them organized in tree
type GrHeap []Group
//To implement your logic you can use stdlib/container/heap Heap interface
//you must implement Heap interface for your slice
func (h GrHeap) Len() int { return len(h) }
func (h GrHeap) Less(i, j int) bool { return h[i].Score < h[j].Score }
func (h GrHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] }
func (h *GrHeap) Push(x interface{}) {
// Push and Pop use pointer receivers because they modify the slice's length,
// not just its contents.
*h = append(*h, x.(Group))
}
func (h *GrHeap) Pop() interface{} {
old := *h
n := len(old)
x := old[n-1]
*h = old[0 : n-1]
return x
}
func main() {
//you most likely already have a map
//anyway it will be handy to keep it for convenient access to individual country
score := map[string]int{
"Canada": 7,
"US": 2,
"Germany": 3,
"Korea": 4,
}
//here we allocate heap
gr := make(GrHeap, 0)
//populate it from map
for k, v := range score {
g := Group{v, nil, nil, k}
gr = append(gr, g)
}
//and initialize
heap.Init(&gr)
//and here we use heap magic to implement your logic
for len(gr) > 2 {
l := heap.Pop(&gr).(Group)
r := heap.Pop(&gr).(Group)
ng := Group{l.Score + r.Score, &l, &r, ""}
heap.Push(&gr, ng)
}
fmt.Println(gr)
fmt.Println(gr[1].Left)
fmt.Println(gr[1].Right.Left)
//and you can see it works https://play.golang.org/p/gugJxJb7rr
}
You can try map[string]interface{} with Type assertion。
Here is the demo
package main
import "fmt"
const total = "total"
func GetValue(i interface{}) int {
value, ok := i.(int)
if ok {
return value
}
return i.(map[string]interface{})[total].(int)
}
func main() {
score := map[string]interface{}{
"Canada": 7,
"US": 2,
"Germany": 3,
"Korea": 4,
}
groupCount := 0
for len(score) > 2 {
var (
firstMin = math.MaxInt32
secondMin = math.MaxInt32
firstKey = ""
secondKey = ""
)
for k, v := range score {
iv := GetValue(v)
if iv < firstMin {
secondMin = firstMin
secondKey = firstKey
firstMin = iv
firstKey = k
continue
}
if iv < secondMin {
secondMin = iv
secondKey = k
continue
}
}
groupCount++
score[fmt.Sprintf("Group%d", groupCount)] = map[string]interface{}{
firstKey: score[firstKey],
secondKey: score[secondKey],
total: GetValue(score[firstKey])+ GetValue(score[secondKey]),
}
delete(score, firstKey)
delete(score, secondKey)
}
fmt.Println(score)
}
Here is the link https://play.golang.org/p/qq5qwAsh1m
This question already has answers here:
Slice chunking in Go
(8 answers)
Closed 8 months ago.
I created a small helper function to split a large array of items into smaller arrays with a maximum size of n.
func toPackages(e []int, n int) [][]int {
var p [][]int
packets := int(math.Ceil(float64(len(e)) / float64(n)))
for i := 0; i < packets; i++ {
start := i * n
end := n * (i + 1)
if len(e) < end {
end = len(e)
}
p = append(p, e[start:end])
}
return p
}
Working example at Golang Playground.
In the program I have several different types of arrays I would like to split. I have tried converting it to using interfaces with interface{}.
It is pretty hard to make a generic function to handle this well. You will often spend as much code converting []int to []interface{} and back, as it is to just copy the snippet. I do have a slightly nicer way to do it though:
playground link
func splitInts(src []int, n int) (p [][]int){
for len(src) > n{
p = append(p,src[:n])
src = src[n:]
}
if(len(src) > 0){
p = append(p,src)
}
return p
}
Nothing in the function changes because of types, it can easily be copied to:
func splitStrings(src []string, n int) (p [][]string){
for len(src) > n{
p = append(p,src[:n])
src = src[n:]
}
if(len(src) > 0){
p = append(p,src)
}
return p
}
By only changing the first line.
Generally it is a good idea to just write the function for every type you need it for. This is also a matter of speed: if you use reflect to write a generic function it will not be as fast.
If you still want a generic function here it is:
func genToPackages(e interface{}, n int) interface{} {
t := reflect.TypeOf(e)
if t.Kind() != reflect.Slice {
log.Println("e has to be a slice")
}
v := reflect.ValueOf(e)
packets := int(math.Ceil(float64(v.Len()) / float64(n)))
p := reflect.MakeSlice(reflect.SliceOf(t), packets, packets)
for i := 0; i < packets; i++ {
s := reflect.MakeSlice(t, n, n)
start := i * n
for j := 0; j < n; j++ {
s.Index(j).Set(v.Index(j+start))
}
p.Index(i).Set(s)
}
return p.Interface()
}
You will have to cast the result to the type you expect. For example:
res := genToPackages([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 5).([][]int)