golang sort slice ascending or descending - sorting

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
}

Related

How can I write a method to reverse any slice? [duplicate]

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)

Sorting array of i by v[i]/w[i] in Go

I would like to sort an array of indices descendingly by v[i]/w[i] where v and w are two other arrays of integers. Here is what I have tried in Go:
package main
import "fmt"
import "sort"
func main() {
v := [3]int{5, 6, 3}
w := [3]int{4, 5, 2}
indices := make([]int, 3)
for i := range indices {
indices[i] = i
}
sort.Slice(indices, func(a, b int) bool {
return float32(v[a])/float32(w[a]) > float32(v[b])/float32(w[b])
})
fmt.Println(indices)
}
I expect the output to be [2,0,1] because 3/2 > 5/4 > 6/5 but the actual output is [0,2,1]. Could anyone help me find the where the problem is? Thank you.
To not mutate v and w arrays which can be expensive, we can just add another level of indirection into the Less function
sort.Slice(indices, func(a, b int) bool {
return float32(v[indices[a]])/float32(w[indices[a]]) > float32(v[indices[b]])/float32(w[indices[b]])
})
Playground
Sorting by definition moves items you're sorting around in the slice, therefore changing their respective indexes. However you are not moving the actual values you are sorting, which are in w and v, only the indices slice.
Since the indices slice contains the sorted "indices", you can use that to lookup the actual value for comparison.
sort.Slice(indices, func(i, j int) bool {
return float64(v[indices[i]])/float64(w[indices[i]]) > float64(v[indices[j]])/float64(w[indices[j]])
})
https://play.golang.org/p/6oFBM27bVR-
Or you could implement a type to sort all 3 values at once for example:
type indexSorter struct {
indices, w, v []int
}
func (a indexSorter) Len() int { return len(a.indices) }
func (a indexSorter) Swap(i, j int) {
a.indices[i], a.indices[j] = a.indices[j], a.indices[i]
a.w[i], a.w[j] = a.w[j], a.w[i]
a.v[i], a.v[j] = a.v[j], a.v[i]
}
func (a indexSorter) Less(i, j int) bool {
return float64(a.v[i])/float64(a.w[i]) > float64(a.v[i])/float64(a.w[j])
}
https://play.golang.org/p/EFUkHWgjo5U
This is happening because the sort function changes the indices while it is sorting but your accompanying arrays v and w remain constant.
The best way to do what you want is to create a single array with v and w both contained in a struct and then order that array.

sorting a uint64 slice in go

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

Get the indices of the array after sorting in golang

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

How do I reverse an array in Go?

http://play.golang.org/p/W70J4GU7nA
s := []int{5, 2, 6, 3, 1, 4}
sort.Reverse(sort.IntSlice(s))
fmt.Println(s)
// 5, 2, 6, 3, 1, 4
It is hard to understand what it means in func Reverse(data Interface) Interface .
How do I reverse an array? I do not need to sort.
Honestly this one is simple enough that I'd just write it out like this:
package main
import "fmt"
func main() {
s := []int{5, 2, 6, 3, 1, 4}
for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
s[i], s[j] = s[j], s[i]
}
fmt.Println(s)
}
http://play.golang.org/p/vkJg_D1yUb
(The other answers do a good job of explaining sort.Interface and how to use it; so I won't repeat that.)
Normally, to sort an array of integers you wrap them in an IntSlice, which defines the methods Len, Less, and Swap. These methods are in turn used by sort.Sort. What sort.Reverse does is that it takes an existing type that defines Len, Less, and Swap, but it replaces the Less method with a new one that is always the inverse of the underlying Less:
type reverse struct {
// This embedded Interface permits Reverse to use the methods of
// another Interface implementation.
Interface
}
// Less returns the opposite of the embedded implementation's Less method.
func (r reverse) Less(i, j int) bool {
return r.Interface.Less(j, i)
}
// Reverse returns the reverse order for data.
func Reverse(data Interface) Interface {
return &reverse{data}
}
So when you write sort.Reverse(sort.IntSlice(s)), whats happening is that you're getting this new, 'modified' IntSlice that has it's Less method replaced. So if you call sort.Sort on it, which calls Less, it will get sorted in decreasing order.
I'm 2 years late, but just for fun and interest I'd like to contribute an "oddball" solution.
Assuming the task really is to reverse a list, then for raw performance bgp's solution is probably unbeatable. It gets the job done simply and effectively by swapping array items front to back, an operation that's efficient in the random-access structure of arrays and slices.
In Functional Programming languages, the idiomatic approach would often involve recursion. This looks a bit strange in Go and will have atrocious performance. That said, here's a recursive array reversal function (in a little test program):
package main
import (
"fmt"
)
func main() {
myInts := []int{ 8, 6, 7, 5, 3, 0, 9 }
fmt.Printf("Ints %v reversed: %v\n", myInts, reverseInts(myInts))
}
func reverseInts(input []int) []int {
if len(input) == 0 {
return input
}
return append(reverseInts(input[1:]), input[0])
}
Output:
Ints [8 6 7 5 3 0 9] reversed: [9 0 3 5 7 6 8]
Again, this is for fun and not production. Not only is it slow, but it will overflow the stack if the list is too large. I just tested, and it will reverse a list of 1 million ints but crashes on 10 million.
First of all, if you want to reverse the array, do like this,
for i, j := 0, len(a)-1; i < j; i, j = i+1, j-1 {
a[i], a[j] = a[j], a[i]
}
Then, look at the usage of Reverse in golang.org
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)
}
// output
// [6 5 4 3 2 1]
And look at the description of Reverse and Sort
func Reverse(data Interface) Interface
func Sort(data Interface)
Sort sorts data. It makes one call to data.Len to determine n, and O(n*log(n)) calls to data.Less and data.Swap. The sort is not guaranteed to be stable.
So, as you know, Sort is not just a sort algorithm, you can view it as a factory, when you use Reverse it just return a reversed sort algorithm, Sort is just doing the sorting.
This is a more generic slice reverse function. It will panic if input is not a slice.
//panic if s is not a slice
func ReverseSlice(s interface{}) {
size := reflect.ValueOf(s).Len()
swap := reflect.Swapper(s)
for i, j := 0, size-1; i < j; i, j = i+1, j-1 {
swap(i, j)
}
}
If you want to reverse the array, you can just go through it in reverse order. Since there is no "reverse range" primitive in the language (at least not yet), you must do something like this (http://play.golang.org/p/AhvAfMjs_7):
s := []int{5, 2, 6, 3, 1, 4}
for i := len(s) - 1; i >= 0; i-- {
fmt.Print(s[i])
if i > 0 {
fmt.Print(", ")
}
}
fmt.Println()
Regarding whether it is hard to understand what sort.Reverse(data Interface) Interface does, I thought the same until I saw the source code from "http://golang.org/src/pkg/sort/sort.go".
It just makes the comparisons required for the sorting to be made "the other way around".
Here is a simple Go solution that uses an efficient (no extra memory) approach to reverse an array:
i := 0
j := len(nums) - 1
for i < j {
nums[i], nums[j] = nums[j], nums[i]
i++
j--
}
The idea is that reversing an array is equivalent to swapping each element with its mirror image across the center.
https://play.golang.org/p/kLFpom4LH0g
Here is another way to do it
func main() {
example := []int{1, 25, 3, 5, 4}
sort.SliceStable(example, func(i, j int) bool {
return true
})
fmt.Println(example)
}
https://play.golang.org/p/-tIzPX2Ds9z
func Reverse(data Interface) Interface
This means that it takes a sort.Interface and returns another sort.Interface -- it doesn't actually doing any sorting itself. For example, if you pass in sort.IntSlice (which is essentially a []int that can be passed to sort.Sort to sort it in ascending order) you'll get a new sort.Interface which sorts the ints in descending order instead.
By the way, if you click on the function name in the documentation, it links directly to the source for Reverse. As you can see, it just wraps the sort.Interface that you pass in, so the value returned from Reverse gets all the methods of the original sort.Interface. The only method that's different is the Less method which returns the opposite of the Less method on the embedded sort.Interface. See this part of the language spec for details on embedded fields.
From Golang wiki SliceTricks:
To replace the contents of a slice with the same elements but in
reverse order:
for i := len(a)/2-1; i >= 0; i-- {
opp := len(a)-1-i
a[i], a[opp] = a[opp], a[i]
}
The same thing, except with two indices:
for left, right := 0, len(a)-1; left < right; left, right = left+1, right-1 {
a[left], a[right] = a[right], a[left]
}
To reverse an array in place, iterate to its mid-point, and swap each element with its "mirror element":
func main() {
xs := []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
itemCount := len(xs)
for i := 0; i < itemCount/2; i++ {
mirrorIdx := itemCount - i -1
xs[i], xs[mirrorIdx] = xs[mirrorIdx], xs[i]
}
fmt.Printf("xs: %v\n", xs)
}
https://play.golang.org/p/JeSApt80_k
Here is a method using append:
package main
import "fmt"
func main() {
a := []int{10, 20, 30, 40, 50}
for n := len(a) - 2; n >= 0; n-- {
a = append(a[:n], append(a[n + 1:], a[n])...)
}
fmt.Println(a)
}
Drawing of the steps:
10 20 30 40 50
10 20 30 50 40
10 20 50 40 30
10 50 40 30 20
50 40 30 20 10
This answer is mainly for those beginners who wish to write this code using only one variable in the for loop instead of using two variables (like i & j).
package main
import "fmt"
func main() {
array := []int{45, 17, 43, 67, 21, 4, 97, 44, 54, 98, 665}
fmt.Println("initial array:", array)
loop_iteration := len(array)
if len(array)%2 == 0 {
loop_iteration = (len(array) / 2) - 1
} else {
loop_iteration = int(len(array) / 2) //This will give the lower integer value of that float number.
}
for i := 0; i <= loop_iteration; i++ {
array[i], array[(len(array)-1)-i] = array[(len(array)-1)-i], array[i]
}
fmt.Println("reverse array:", array)
}
https://go.dev/play/p/bVp0x7v6Kbs
package main
import (
"fmt"
)
func main() {
arr := []int{1, 2, 3, 4, 5}
fmt.Println(reverseArray(arr))
}
func reverseArray(arr []int) []int {
reversed := make([]int, len(arr))
j := 0
for i := len(arr) - 1; i >= 0; i-- {
reversed[j] = arr[i]
j++
}
return reversed
}
Simple solution without involving math. Like this solution, this is inefficient as it does too much allocation and garbage collection. Good for non-critical code where clarity is more important than performance. Playground: https://go.dev/play/p/dQGwrc0Q9ZA
arr := []int{1, 3, 4, 5, 6}
var rev []int
for _, n := range arr {
rev = append([]int{n}, rev...)
}
fmt.Println(arr)
fmt.Println(rev)
Its very simple if you want to print reverse array
Use Index from length doing i--
ex.
a := []int{5, 4, 12, 7, 15, 9}
for i := 0; i <= len(a)-1; i++ {
fmt.Println(a[len(a)-(i+1)])
}
https://go.dev/play/p/bmyFh7-_VCZ
Here is my solution.
package main
import (
"fmt"
)
func main() {
var numbers = [10]int {1,2,3,4,5,6,7,8,9,10}
var reverseNumbers [10]int
j:=0
for i:=len(numbers)-1; i>=0 ; i-- {
reverseNumbers[j]=numbers[i]
j++
}
fmt.Println(reverseNumbers)
}
Here is my solution to reversing an array:
func reverse_array(array []string) []string {
lenx := len(array) // lenx holds the original array length
reversed_array := make([]string, lenx) // creates a slice that refer to a new array of length lenx
for i := 0; i < lenx; i++ {
j := lenx - (i + 1) // j initially holds (lenx - 1) and decreases to 0 while i initially holds 0 and increase to (lenx - 1)
reversed_array[i] = array[j]
}
return reversed_array
}
You can try this solution on the go playground the go playground
package main
import "fmt"
func main() {
array := []string{"a", "b", "c", "d"}
fmt.Println(reverse_array(array)) // prints [d c b a]
}
Do not reverse it, leave it as now and then just iterate it backwards.

Resources