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 ?
In Java there is a PriorityQueue with size attribute. I'm expecting the same here (if I'm not wrong).
Use case: Read millions of data one by one and send it to a priority queue. I want only the top 5 calculated elements so I want a heap/priority queue of size 5 only.
I'm trying to use heap interface to achieve this. As to what I see golang does dynamic array increase but this is not feasible in my case.
I am referring to https://play.golang.org/p/wE413xwmxE
How can I achieve this?
If you just want top M smallest elements from N elements then use the heap that would give you the biggest element and prune the heap whenever its size goes over value M. Then take elements from the heap in reverse order.
package main
import (
"container/heap"
"fmt"
"math/rand"
)
type IntHeap []int
func (h IntHeap) Len() int { return len(h) }
func (h IntHeap) Less(i, j int) bool { return h[i] > h[j] }
func (h IntHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] }
func (h *IntHeap) Push(x interface{}) {
*h = append(*h, x.(int))
}
func (h *IntHeap) Pop() interface{} {
old := *h
n := len(old)
x := old[n-1]
*h = old[0 : n-1]
return x
}
const (
n = 1000000
m = 5
)
func main() {
h := &IntHeap{}
heap.Init(h)
for i := 0; i < n; i++ {
x := rand.Intn(n)
heap.Push(h,x)
if h.Len() > m {
heap.Pop(h)
}
}
r := make([]int, h.Len())
for i := len(r) - 1; i >= 0; i-- {
r[i] = heap.Pop(h).(int)
}
fmt.Printf("%v\n", r)
}
This algorithm has memory complexity of M and time complexity of N + N * log M + M * log M.
I want the strings to be sorted alphabetically with control over whether "A" comes before "a".
In the Less() function using strings.ToLower() doesn't achieve this. Sometimes "A" comes before "a", and sometimes after.
instead of comparing the entire string using strings.ToLower, compare the individual runes.
https://play.golang.org/p/RUMlmrb7C3g
type ByCase []string
func (s ByCase) Len() int { return len(s) }
func (s ByCase) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (s ByCase) Less(i, j int) bool {
iRunes := []rune(s[i])
jRunes := []rune(s[j])
max := len(iRunes)
if max > len(jRunes) {
max = len(jRunes)
}
for idx := 0; idx < max; idx++ {
ir := iRunes[idx]
jr := jRunes[idx]
lir := unicode.ToLower(ir)
ljr := unicode.ToLower(jr)
if lir != ljr {
return lir < ljr
}
// the lowercase runes are the same, so compare the original
if ir != jr {
return ir < jr
}
}
// If the strings are the same up to the length of the shortest string,
// the shorter string comes first
return len(iRunes) < len(jRunes)
}
This may be a solution:
package main
import (
"strings"
"sort"
"fmt"
)
var listOfStrings []string = []string{
"mars bar",
"milk-duds",
"Mars bar",
"milk",
"milky-way",
"Milk",
"Milky-way",
"mars",
}
type Alphabetic []string
func (list Alphabetic) Len() int { return len(list) }
func (list Alphabetic) Swap(i, j int) { list[i], list[j] = list[j], list[i] }
func (list Alphabetic) Less(i, j int) bool {
var si string = list[i]
var sj string = list[j]
var si_lower = strings.ToLower(si)
var sj_lower = strings.ToLower(sj)
if si_lower == sj_lower {
return si < sj
}
return si_lower < sj_lower
}
func main() {
fmt.Println("UNSORTED")
printStrings(listOfStrings)
sort.Sort(Alphabetic(listOfStrings))
fmt.Println()
fmt.Println("SORTED ALPHABETICALLY")
printStrings(listOfStrings)
}
func printStrings(slice []string) {
for i := 0; i < len(slice); i++ {
fmt.Println(slice[i])
}
}
Here's the output:
UNSORTED
mars bar
milk-duds
Mars bar
milk
milky-way
Milk
Milky-way
mars
SORTED ALPHABETICALLY
mars
Mars bar
mars bar
Milk
milk
milk-duds
Milky-way
milky-way
Heres a Unicode friendly method that utilizes strings.Map:
package main
import (
"fmt"
"sort"
"strings"
"unicode"
)
type slice struct { sort.StringSlice }
func (s slice) Less(d, e int) bool {
t := strings.Map(unicode.ToUpper, s.StringSlice[d])
u := strings.Map(unicode.ToUpper, s.StringSlice[e])
return t < u
}
func main() {
a := slice{
sort.StringSlice{"a", "b", "A", "B"},
}
sort.Sort(a)
fmt.Println(a.StringSlice) // [a A b B]
}
https://golang.org/pkg/strings#Map
I am attempting to have two variations of the sort method: one form which sorts the elements by name, and another that sorts the elements by salary. sort.Sort(people(data)) works when my less method compares whatever.salary. It also works if I change it to whatever.name. I would like to be able to specifically call both of these options in the less method as shown in the below code. My logic is using sort.Sort(people(data.name)) for name, and sort.Sort(people(data.salary)) for salary. These are not working. Can this even be done?
package main
import (
"fmt"
"sort"
)
type Comparable interface {
Len()
Less(i, j int) bool
Swap(i, j int)
}
type person struct {
name string
salary float64
}
func (a person) String() string {
return fmt.Sprintf("%s: %g \n", a.name, a.salary)
}
type people []*person
func (a people) Len() int {
return len(a)
}
func (a people) Less(i, j int) bool {
return a[i].salary < a[j].salary
return a[i].name < a[j].name
}
func (a people) Swap(i, j int) {
a[i], a[j] = a[j], a[i]
}
func main() {
var data = make(people, 10)
var a, b, c, d, e, f, g, h, i, j person
a.name, b.name, c.name, d.name, e.name, f.name,
g.name, h.name, i.name, j.name = "Sheila Broflovski", "Ben Affleck",
"Mr. Hankey", "Stan Marsh", "Kyle Broflovski", "Eric Cartman",
"Kenny McCormick", "Mr. Garrison", "Matt Stone", "Trey Parker"
a.salary, b.salary, c.salary, d.salary, e.salary, f.salary,
g.salary, h.salary, i.salary, j.salary = 82000, 74000, 0, 400,
2500, 1000, 4, 34000, 234000, 234000
a.salary = 82000
data[0] = &a
data[1] = &b
data[2] = &c
data[3] = &d
data[4] = &e
data[5] = &f
data[6] = &g
data[7] = &h
data[8] = &i
data[9] = &j
fmt.Println("\n\n\n")
fmt.Print(data)
sort.Sort(people(data)) //This works even with the two return statements
sort.Sort(people(data.name)) //This does not work. Exist, a version that does?
sort.Sort(people(data.salary)) //This does not work. Exist, a version that does?
fmt.Println("\n\n\n")
fmt.Print(data)
}
A common way to introduce the methods for sorting is to use a new type that describes the sorting condition. That's byName and bySalary here. Then you can sort using sort.Sort(byName(data)).
Here's some demonstration code. Go also has really great good for constructing data-structures (used prolifically, for example, in table-driven tests), which also can help construct your people data here.
package main
import "fmt"
import "sort"
type person struct {
Name string
Salary float64
}
type people []*person
type byName people
type bySalary people
func (p byName) Len() int { return len(p) }
func (p byName) Less(i, j int) bool { return p[i].Name < p[j].Name }
func (p byName) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
func (p bySalary) Len() int { return len(p) }
func (p bySalary) Less(i, j int) bool { return p[i].Salary < p[j].Salary }
func (p bySalary) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
func main() {
p := people{
{"Sheila Broflovski", 82000},
{"Ben Affleck", 74000},
{"Mr. Hankey", 0},
{"Stan Marsh", 400},
{"Kyle Broflovski", 2500},
{"Eric Cartman", 1000},
{"Kenny McCormick", 4},
{"Mr. Garrison", 34000},
{"Matt Stone", 234000},
{"Trey Parker", 234000},
}
fmt.Println("by name")
sort.Sort(byName(p))
for _, x := range p {
fmt.Println(*x)
}
fmt.Println("by salary")
sort.Sort(bySalary(p))
for _, x := range p {
fmt.Println(*x)
}
}
To implement a second sort ordering with the standard library sort package, you will need to define a helper type that implements sort.Interface. To handle the salary case in your example, you could do something like the following:
type bySalary struct {
people
}
func (s bySalary) Less(i, j int) bool {
return s.people[i].salary < s.people[j].salary
}
Here, the Len and Swap methods required by sort.Interface come from the embedded people slice, while I've provided a replacement comparison operation. To sort a people array, you can now call:
sort.Sort(bySalary{data})
Using this pattern, it is easy to implement as many additional sort keys as you need with very little duplicate code.
You can play with this example here: http://play.golang.org/p/kq3SuXMylT
I'm puzzled as why this code doesn't work:
package main
import (
"fmt"
"sort"
)
type T [2]int
func (t T) Len() int { return len(t) }
func (t T) Swap(i, j int) { t[i], t[j] = t[j], t[i] }
func (t T) Less(i, j int) bool { return t[i] < t[j] }
func main() {
var x = [2]int{1, 0}
fmt.Println(x)
sort.Sort(T(x))
fmt.Println(x)
}
It outputs (incorrectly):
[1 0]
[1 0]
Changing the type of T to slices does the correct thing.
Slices are inherently reference types, meaning the slice header contains a pointer to the backing array, so they can be mutated without a pointer receiver. Arrays not being a reference type, are copied in full when calling your methods.
In order to do this with an array you need to change everything to use pointers, so your code might look something like:
package main
import (
"fmt"
"sort"
)
type T [2]int
func (t *T) Len() int { return len(t) }
func (t *T) Swap(i, j int) { t[i], t[j] = t[j], t[i] }
func (t *T) Less(i, j int) bool { return t[i] < t[j] }
func main() {
var x = T([2]int{1, 0})
fmt.Println(x)
sort.Sort(&x)
fmt.Println(x)
}