I'm writing Go application using Go 1.7rc3.
I have a slice of uint64 (var dirRange []uint64) that I want to sort.
The sort package has a function sort.Ints() but it requires []int and I have []uint64.
What do I do? Can I type cast the all slice?
As of version 1.8, you can use the simpler function sort.Slice. In your case, it would be something like the following:
sort.Slice(dirRange, func(i, j int) bool { return dirRange[i] < dirRange[j] })
This avoids having to define any type just for the sorting.
You can define sort.Interface on your dirRange, which can be a type aliasing []uint64:
type DirRange []uint64
func (a DirRange) Len() int { return len(a) }
func (a DirRange) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a DirRange) Less(i, j int) bool { return a[i] < a[j] }
func main() {
dirRange := DirRange{2, 5, 7, 1, 9, 4}
sort.Sort(dirRange)
fmt.Println(dirRange)
}
Output:
[1 2 4 5 7 9]
This way you can avoid casting and work directly with your array. Since the underlying type is a slice []uint64, you can still use general slice operations. For example:
dirRange := make(DirRange, 10)
dirRange = append(dirRange, 2)
You can provide a type alias for []uint64, add the standard "boilerplate" sorting methods to implement sort.interface (Len, Swap, and Less - https://golang.org/pkg/sort/#Interface); then either create an instance of the new type or typecast an existing slice []uint64 into the new type, as done in the following example (also https://play.golang.org/p/BbB3L9TmBI):
package main
import (
"fmt"
"sort"
)
type uint64arr []uint64
func (a uint64arr) Len() int { return len(a) }
func (a uint64arr) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a uint64arr) Less(i, j int) bool { return a[i] < a[j] }
func (a uint64arr) String() (s string) {
sep := "" // for printing separating commas
for _, el := range a {
s += sep
sep = ", "
s += fmt.Sprintf("%d", el)
}
return
}
func main() {
dirRange := []uint64{3, 2, 400000}
arr := uint64arr(dirRange)
sort.Sort(arr)
fmt.Printf("%s\n", arr)
fmt.Printf("%#v\n", dirRange)
}
The output is:
2, 3, 400000
[]uint64{0x2, 0x3, 0x61a80}
showing that both arrays are sorted since the second one is a typecasted alias for the original.
There is no wrapper function, you need to use the Slice function, and this is an example:
arr := []uint64{5, 0, 3, 2, 1, 6}
sort.Slice(arr, func(i, j int) bool { return arr[i] < arr[j] })
Related
This question already has answers here:
How do I reverse a slice in go?
(6 answers)
Closed 10 months ago.
What's the idiomatic way to write a method that operates on a "generic" array?
I have a typed array:
a := make([]int, 0)
I want to write a simple method that could operate on an array of any type:
func reverse(a []interface{}) []interface{} {
for i, j := 0, len(a)-1; i < j; i, j = i+1, j-1 {
a[i], a[j] = a[j], a[i]
}
return a
}
Using this method a = reverse(a) gives me 2 errors:
cannot use a (type []int) as type []interface {} in argument to reverse
cannot use reverse(a) (type []interface {}) as type []int in assignment
Not that you can use generic in production as of now (as of 2nd Oct 2020) but for people interested in the upcoming go generics feature, with the latest design draft of go, you can write a generic function reverse as below
package main
import (
"fmt"
)
func reverse[T any](s []T) []T {
for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
s[i], s[j] = s[j], s[i]
}
return s
}
func main() {
s := []int{1, 2, 3, 4, 5}
s = reverse(s)
fmt.Println(s)
}
Output:
[5 4 3 2 1]
Until generics arrive (which will most likely be called contracts), reflection and interfaces are the only tools to achieve such generalization.
You could define reverse() to take a value of interface{} and use the reflect package to index it and swap elements. This is usually slow, and harder to read / maintain.
Interfaces provide a nicer way but requires you to write methods to different types. Take a look at the sort package, specifically the sort.Sort() function:
func Sort(data Interface)
Where sort.Interface is:
type Interface interface {
// Len is the number of elements in the collection.
Len() int
// Less reports whether the element with
// index i should sort before the element with index j.
Less(i, j int) bool
// Swap swaps the elements with indexes i and j.
Swap(i, j int)
}
sort.Sort() is able to sort any slices that implement sort.Interface, any slices that have the methods the sorting algorithm needs to do its work. The good thing about this approach is that you can sort other data structures too not just slices (e.g. a linked list or an array), but usually slices are used.
Patience! According to the latest draft proposal to add type parameters to the language, you will be able to write such a generic reverse function in a future version of Go:
func reverse[T any](s []T) []T {
for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
s[i], s[j] = s[j], s[i]
}
return s
}
func main() {
s := []int{1, 2, 3, 4, 5}
s = reverse(s)
fmt.Println(s)
}
(playground)
For performance reasons, you may want to reverse the slice in place:
package main
import "fmt"
func reverse[T any](s []T) {
for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
s[i], s[j] = s[j], s[i]
}
}
func main() {
s := []int{1, 2, 3, 4, 5}
reverse(s)
fmt.Println(s)
}
(playground)
I have slice as below
{string, int }
[{zaa 1} {aab 1} {xac 1}]
in this case int side equal so no I need to sort using alphabetical order
if my slice like bellow
[{zaa 1} {aab 4} {xac 2}]
I need to sort using numeric value, how can I do this?
Right now I'm using sort given by golang
type ByStringValue []string
type ByNumericValue []WeightBaseResourceInfo
func (a ByStringValue) Len() int { return len(a) }
func (a ByStringValue) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a ByStringValue) Less(i, j int) bool { return a[i] < a[j] }
func (a ByNumericValue) Len() int { return len(a) }
func (a ByNumericValue) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a ByNumericValue) Less(i, j int) bool {
w1 := a[i].Weight
w2 := a[j].Weight
return w1 > w2
}
For sorting slices, simply use sort.Slice(), added in Go 1.8.
To use sort.Slice() you only need to provide a comparator function, which must tell if an element is less than another.
The logic inside the less() function should test the numbers first, if they differ, the numbers should decide the result. If they are equal, then compare the text values to tell if one is less than the other.
For example:
type Entry struct {
Text string
Number int
}
func main() {
es := []Entry{
{"zaa", 1}, {"aab", 1}, {"xac", 1},
{"zaa", 1}, {"aab", 4}, {"xac", 2},
}
sort.Slice(es, func(i, j int) bool {
if a, b := es[i].Number, es[j].Number; a != b {
return a < b
}
return es[i].Text < es[j].Text
})
fmt.Println(es)
}
Output (try it on the Go Playground):
[{aab 1} {xac 1} {zaa 1} {zaa 1} {xac 2} {aab 4}]
type ByName []WeightBaseResourceInfo
func (a ByName) Len() int { return len(a) }
func (a ByName) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a ByName) Less(i, j int) bool { return a[i].ResourceId < a[j].ResourceId }
func main() {
resourceWeightInfo := make([]WeightBaseResourceInfo, 3)
start := make([]WeightBaseResourceInfo, 3)
var tempWeightInfo WeightBaseResourceInfo
tempWeightInfo.ResourceId = "zaa"
tempWeightInfo.Weight = 2
resourceWeightInfo[0] = tempWeightInfo
tempWeightInfo.ResourceId = "aab"
tempWeightInfo.Weight = 5
resourceWeightInfo[1] = tempWeightInfo
tempWeightInfo.ResourceId = "xac"
tempWeightInfo.Weight = 1
resourceWeightInfo[2] = tempWeightInfo
copy(start,resourceWeightInfo)
fmt.Println("start", start)
sort.Sort(ByNumericValue(resourceWeightInfo))
if(reflect.DeepEqual(start,resourceWeightInfo)){
sort.Sort(ByName(resourceWeightInfo))
}
fmt.Println("Sorted", resourceWeightInfo)
}
import "reflect"
I need to sort a slice of a type that is coming from a 3rdparty package. Based on some condition the order must be ascending or descending.
The solution I come up with is:
type fooAscending []foo
func (v fooAscending) Len() int { return len(v) }
func (v fooAscending) Swap(i, j int) { v[i], v[j] = v[j], v[i] }
func (v fooAscending) Less(i, j int) bool { return v[i].Amount < v[j].Amount }
type fooDescending []foo
func (v fooDescending) Len() int { return len(v) }
func (v fooDescending) Swap(i, j int) { v[i], v[j] = v[j], v[i] }
func (v fooDescending) Less(i, j int) bool { return v[i].Amount > v[j].Amount }
if someCondition {
sort.Sort(fooAscending(array))
} else {
sort.Sort(fooDescending(array))
}
Is there a better way to do this. 13 lines of code for this task and most of it is duplicated, seems a bit too much.
As of Go 1.8, there is an easier way to sort a slice that does not require you to define new types. You simply pass an anonymous function to the sort.Slice function.
a := []int{5, 3, 4, 7, 8, 9}
sort.Slice(a, func(i, j int) bool {
return a[i] < a[j]
})
for _, v := range a {
fmt.Println(v)
}
This will sort in ascending order, if you want the opposite, simply write a[i] > a[j] in the anonymous function.
You're looking for sort.Reverse. That will let you say:
sort.Sort(sort.Reverse(fooAscending(s)))
My answer below is based on the assumption that the slice that you are receiving from a third party package is of a basic Go type.
To sort slices of basic types, use the sort package utilities. Here is an example that sorts a slice of string and a slice of int.
package main
import (
"fmt"
"sort"
)
func main() {
sl := []string{"mumbai", "london", "tokyo", "seattle"}
sort.Sort(sort.StringSlice(sl))
fmt.Println(sl)
intSlice := []int{3,5,6,4,2,293,-34}
sort.Sort(sort.IntSlice(intSlice))
fmt.Println(intSlice)
}
The output of the above is:
[london mumbai seattle tokyo]
[-34 2 3 4 5 6 293]
Go to Go Playground here to try it out yourself.
A few things of note:
Sorting basic Go types does not require implementing functions such as Len() that belong to sort.Interface. You need to take that route only for composite types.
Just wrap the type of a basic type using an appropriate Interface method provider, e.g. StringSlice, IntSlice, or Float64Slice, and sort.
The slice is sorted in-place, and hence does not return a copy of the sorted slice.
you can import the "sort" package from standard library of golang . then you can use either "Slice" or "SliceStable" function to sort your slice. it is recommended to use the second one like this :
sort.SliceStable(yourSlice , anonnymousFunction)
example :
package main
import (
"fmt"
"sort"
)
func main() {
a := []int{4,5,9,6,8,3,5,7,99,58,1}
sort.SliceStable(a, func(i,j int )bool{
//i,j are represented for two value of the slice .
return a[i] < a[j]
})
fmt.Println(a)
}
The accepted answer is good, but I disagree with their suggestion on descending:
a[i] > a[j]
With sort.Slice, the provided function is supposed to represent an
implementation of "less than":
func Slice(x interface{}, less func(i, j int) bool)
Slice sorts the slice x given the provided less function. It panics if x is not a slice.
So writing a "greater than" function, isn't really true to the given description. Better would be to reverse the indexes:
package main
import (
"fmt"
"sort"
)
func main() {
a := []int{5, 3, 4, 7, 8, 9}
sort.Slice(a, func(i, j int) bool {
return a[j] < a[i]
})
fmt.Println(a) // [9 8 7 5 4 3]
}
both should return the same result, but I think one is more idiomatic.
https://golang.org/pkg/sort#Slice
maybe you could use sort.Sort method to sort slice. :)
func TestSorted(t *testing.T) {
nums := []int{4, 3, 2, 3, 5, 2, 1}
// descending
sort.Sort(sort.Reverse(sort.IntSlice(nums)))
fmt.Println(nums) // [5 4 3 3 2 2 1]
// ascending
sort.Sort(sort.IntSlice(nums))
fmt.Println(nums) // [1 2 2 3 3 4 5]
}
var names = []string{"b", "a", "e", "c", "d"}
sort.Strings(names)
fmt.Println("Sorted in alphabetical order", names)
sort.Sort(sort.Reverse(sort.StringSlice(names)))
fmt.Println("Sorted in reverse order", names)
link for The Go Playgound https://play.golang.org/p/Q8KY_JE__kx
if for any reasons you can't or don't want to use the sort package, the following will implement a bubble sort type of sorting (it accepts an int64 slice and returns an int64 slice):
func sortSlice ( S []int64 ) []int64 {
// sort using bubblesort, comparing each pairs of numbers and ensuring that left is lower than right
for i := len(S); i > 0 ; i-- {
for j := 1; j < i; j++ {
if S[j-1] > S[j] {
// swap
intermediate := S[j]
S[j] = S[j-1]
S[j-1] = intermediate
}
}
}
return S
}
This question already has answers here:
How do I reverse a slice in go?
(6 answers)
Closed 11 months ago.
I don't understand what is wrong with the below implementation, I had a look at sort.StringSlice and it looks the same.
type RevStr []string
func(s RevStr) Len() int { return len(s) }
func(s RevStr) Less(i, j int) bool { return s[i] < s[j] }
func(s RevStr) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func Reverse(input string) string {
rs := RevStr(strings.Split(input, " "))
sort.Reverse(rs)
return strings.Join(rs, " ")
}
sort.Reverse doesn't sort the data, but rather returns a new sort.Interface that will sort the data in reverse order. So you don't really need your own type:
func Reverse(input string) string {
s := strings.Split(input, " ")
sort.Sort(sort.Reverse(sort.StringSlice(s)))
return strings.Join(s, " ")
}
Playground: http://play.golang.org/p/w49FDCEHo3.
EDIT: If you just need to reverse a slice of strings, just do:
func reverse(ss []string) {
last := len(ss) - 1
for i := 0; i < len(ss)/2; i++ {
ss[i], ss[last-i] = ss[last-i], ss[i]
}
}
Playground: http://play.golang.org/p/UptIRFV_SI
Nothing is wrong with your RevStr type (though you could just use sort.StringSlice). You're not calling sort.Sort on the reversed implementation:
https://golang.org/pkg/sort/#example_Reverse
package main
import (
"fmt"
"sort"
)
func main() {
s := []int{5, 2, 6, 3, 1, 4} // unsorted
sort.Sort(sort.Reverse(sort.IntSlice(s)))
fmt.Println(s)
}
Although #Ainar-G has provided a way to reverse a slice of strings, I think it's nicer to use two variables in for loop to reverse. But it's only my personal opinion, a matter of style :)
func reverse(s []string) []string {
for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
s[i], s[j] = s[j], s[i]
}
return s
}
Playground link with example of usage: http://play.golang.org/p/v1Cy61NFv1
A one-liner solution (using a lambda):
Given:
myStrings := []string{"apple", "banana", "cherry"}
Sort (in reverse order) with:
sort.Slice(myStrings, func(i, j int) bool { return myStrings[i] > myStrings[j]})
Playground Example:
https://play.golang.org/p/WZabAZTizHG
More simple way, without using built-in sorting feature :
func reverse(s []string) []string {
for i := len(s) - 1; i >= 0; i-- {
result = append(result, s[i])
}
return s
}
func reverseStr(data []string) []string {
m := len(data) - 1
var out = []string{}
for i := m; i >= 0; i-- {
out = append(out, data[i])
}
return out
}
I know we can use
sort.Sort(sort.Reverse(sort.IntSlice(example)))
to sort a array.
But how can I get the indices of the array?
e.g.
example := []int{1, 25, 3, 5, 4}
I want to get the output: 1, 3, 5, 4, 2
Make a wrapper for sort.IntSlice that remembers the indexes and swaps them when it swaps the values:
type Slice struct {
sort.IntSlice
idx []int
}
func (s Slice) Swap(i, j int) {
s.IntSlice.Swap(i, j)
s.idx[i], s.idx[j] = s.idx[j], s.idx[i]
}
Playground: http://play.golang.org/p/LnSLfe-fXk.
EDIT: As DaveC mentioned in the comments, you can actually wrap around sort.Interface to create a data structure for any sortable type:
type Slice struct {
sort.Interface
idx []int
}
func (s Slice) Swap(i, j int) {
s.Interface.Swap(i, j)
s.idx[i], s.idx[j] = s.idx[j], s.idx[i]
}
The accepted answer is good! But I needed a version of it that "didn't touch" my slice.
You can do it like this:
type sortable struct {
nums, idxs []int
}
func (s sortable) Len() int { return len(s.nums) }
func (s sortable) Less(i, j int) bool { return s.nums[i] < s.nums[j] }
func (s sortable) Swap(i, j int) {
s.nums[i], s.nums[j] = s.nums[j], s.nums[i]
s.idxs[i], s.idxs[j] = s.idxs[j], s.idxs[i]
}
func sortAndReturnIdxs(nums []int) []int {
idxs := make([]int, len(nums))
for i := range idxs {
idxs[i] = i
}
sort.Sort(sortable{nums, idxs})
return idxs
}
And then you can just call the function on your slice:
func main() {
nums := []int{4, 1, 6}
fmt.Println(sortAndReturnIdxs(nums)) // [1 0 2]
fmt.Println(nums) // [1 4 6]
}
The function returns the indices, and sorts the array in place.
Playground link: https://go.dev/play/p/7tli8tNeWNt
You can also just get the indices and avoid mutating the slice in-place, see https://github.com/mkmik/argsort