'How do I reverse a slice in go?

How do I reverse an arbitrary slice ([]interface{}) in Go? I'd rather not have to write Less and Swap to use sort.Reverse. Is there a simple, builtin way to do this?

go


Solution 1:[1]

The standard library does not have a built-in function for reversing a slice. Use a for loop to reverse a slice:

for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
    s[i], s[j] = s[j], s[i]
}

Use type parameters to write a generic reverse function in Go 1.18 or later:

func reverse[S ~[]E, E any](s S)  {
    for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
        s[i], s[j] = s[j], s[i]
    }
}

Use reflect.Swapper to write a function that works with arbitrary slice types in Go version 1.8 or later:

func reverse(s interface{}) {
    n := reflect.ValueOf(s).Len()
    swap := reflect.Swapper(s)
    for i, j := 0, n-1; i < j; i, j = i+1, j-1 {
        swap(i, j)
    }
}

Run the code on the Go playground.

The functions in this answer reverse the slice inplace. If you do not want to modify the original slice, copy the slice before reversing the slice.

Solution 2:[2]

This will return a reversed slice without modifying the original slice.

Algorithm used from official wiki page: https://github.com/golang/go/wiki/SliceTricks#reversing

func reverse(s []interface{}) []interface{} {
    a := make([]interface{}, len(s))
    copy(a, s)

    for i := len(a)/2 - 1; i >= 0; i-- {
        opp := len(a) - 1 - i
        a[i], a[opp] = a[opp], a[i]
    }

    return a
}

Solution 3:[3]

There are my code example, you can run it in playground

package main

import (
    "fmt"
    "reflect"
    "errors"
)

func ReverseSlice(data interface{}) {
    value := reflect.ValueOf(data)
    if value.Kind() != reflect.Slice {
        panic(errors.New("data must be a slice type"))
    }
    valueLen := value.Len()
    for i := 0; i <= int((valueLen-1)/2); i++ {
        reverseIndex := valueLen - 1 - i
        tmp := value.Index(reverseIndex).Interface()
        value.Index(reverseIndex).Set(value.Index(i))
        value.Index(i).Set(reflect.ValueOf(tmp))
    }
}


func main() {
    names := []string{"bob", "mary", "sally", "michael"}
    ReverseSlice(names)
    fmt.Println(names)
}

Solution 4:[4]

Here is the function I'm using with generics (go 1.18+). You can use it to reverse any kind of slice or even a string (using the split/join trick). It doesn't change the original slice.

package main

import (
    "fmt"
    "strings"
)

func Reverse[T any](original []T) (reversed []T) {
    reversed = make([]T, len(original))
    copy(reversed, original)

    for i := len(reversed)/2 - 1; i >= 0; i-- {
        tmp := len(reversed) - 1 - i
        reversed[i], reversed[tmp] = reversed[tmp], reversed[i]
    }

    return
}

func main() {
    a := []string{"a", "b", "c"}
    fmt.Println(a, Reverse(a))

    b := []uint{0, 1, 2}
    fmt.Println(b, Reverse(b))

    c := "abc"
    fmt.Println(c, strings.Join(Reverse(strings.Split(c, "")), ""))
}

Better Go Playground

Solution 5:[5]

Here's another possible way to reverse generic slice (go 1.18)

// You can edit this code!
// Click here and start typing.
package main

import (
    "fmt"
    "sort"
)

func main() {
    nums := []int64{10, 5, 15, 20, 1, 100, -1}
    ReverseSlice(nums)
    fmt.Println(nums)

    strs := []string{"hello", "world"}
    ReverseSlice(strs)
    fmt.Println(strs)

    runes := []rune{'h', 'e', 'l', 'l', 'o', 'w', 'o', 'r', 'l', 'd'}
    ReverseSlice(runes)
    for _, r := range runes {
        fmt.Print(string(r), " ")
    }
}

func ReverseSlice[T comparable](s []T) {
    sort.SliceStable(s, func(i, j int) bool {
        return i > j
    })
}

Running the program above should output:

[-1 100 1 20 15 5 10]
[world hello]
d l r o w o l l e h 
Program exited.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 mzarrugh
Solution 3 MIchael
Solution 4 Stefanos Chrs
Solution 5 alextanhongpin