golang sort slice ascending or descending

SortingGo

Sorting Problem Overview


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.

Sorting Solutions


Solution 1 - Sorting

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.

Solution 2 - Sorting

You're looking for sort.Reverse. That will let you say:

sort.Sort(sort.Reverse(fooAscending(s)))

Solution 3 - Sorting

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:

  1. 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.

  2. Just wrap the type of a basic type using an appropriate Interface method provider, e.g. StringSlice, IntSlice, or Float64Slice, and sort.

  3. The slice is sorted in-place, and hence does not return a copy of the sorted slice.

Solution 4 - Sorting

The accepted answer is good, but I disagree with their suggestion on descending:

a[i] > a[j]

With sort.Slice, the provided function is suppposed 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, isnt 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

Solution 5 - Sorting

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

Solution 6 - Sorting

`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

Solution 7 - Sorting

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
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestiongsfView Question on Stackoverflow
Solution 1 - SortingFranck JeanninView Answer on Stackoverflow
Solution 2 - SortingcnicutarView Answer on Stackoverflow
Solution 3 - Sortinguser1820956View Answer on Stackoverflow
Solution 4 - SortingZomboView Answer on Stackoverflow
Solution 5 - SortingMahdi zarepoorView Answer on Stackoverflow
Solution 6 - SortingGolangView Answer on Stackoverflow
Solution 7 - Sortinguser17378908View Answer on Stackoverflow