The Go Cookbook

Maintained by SuperOrbital.

A community built and contributed collection of practical recipes for real world Golang development.

View project on GitHub

Reversing an Array

How do I reverse an array?

Reversing an array is fairly straightforward in Go, due to multiple return values. Simply loop through the first half of the array, swapping each element in turn with its mirror counterpart:

test_simple.go
package main

import "fmt"

func reverse(numbers []int) []int {
	for i := 0; i < len(numbers)/2; i++ {
		j := len(numbers) - i - 1
		numbers[i], numbers[j] = numbers[j], numbers[i]
	}
	return numbers
}

func main() {
	fmt.Printf("%v\n", reverse([]int{1, 2, 3, 4, 5}))
	fmt.Printf("%v\n", reverse([]int{1, 2, 3, 4}))
}
$ go run test_simple.go
[5 4 3 2 1]
[4 3 2 1]

There’s an even more terse implementation which makes use of the , operator inside the Go for loop:

test_terse.go
package main

import "fmt"

func reverse(numbers []int) []int {
	for i, j := 0, len(numbers)-1; i < j; i, j = i+1, j-1 {
		numbers[i], numbers[j] = numbers[j], numbers[i]
	}
	return numbers
}

func main() {
	fmt.Printf("%v\n", reverse([]int{1, 2, 3, 4, 5}))
	fmt.Printf("%v\n", reverse([]int{1, 2, 3, 4}))
}
$ go run test_terse.go
[5 4 3 2 1]
[4 3 2 1]

Note that both of these reverse functions take slices, which are passed by value. This is good for performance, but means we’re actually modifying the passed in array, leading to unexpected results. In other words, the reverse method could be written like such:

test_alternate.go
package main

import "fmt"

func reverse(numbers []int) {
	for i, j := 0, len(numbers)-1; i < j; i, j = i+1, j-1 {
		numbers[i], numbers[j] = numbers[j], numbers[i]
	}
}

func main() {
	array := []int{1, 2, 3, 4, 5}
	reverse(array)

	fmt.Printf("%v\n", array)
}
$ go run test_alternate.go
[5 4 3 2 1]

Now reverse doesn’t return another reference to the slice, which makes it much more clear that it’s modifying the slice in-place. If we want to return a modified copy of the slice, we must do so manually:

test_copy.go
package main

import "fmt"

func reverse(numbers []int) []int {
	newNumbers := make([]int, len(numbers))
	for i, j := 0, len(numbers)-1; i <= j; i, j = i+1, j-1 {
		newNumbers[i], newNumbers[j] = numbers[j], numbers[i]
	}
	return newNumbers
}

func main() {
	array := []int{1, 2, 3, 4, 5}

	fmt.Printf("%v\n", reverse(array))
	fmt.Printf("%v\n", array)
}
$ go run test_copy.go
[5 4 3 2 1]
[1 2 3 4 5]

As you can see in the output above, the original array is untouched.

Since we’re not modifying the array in-place, we can also simplify our algorithm buy doing a more straight-forward element copy:

test_copy_simple.go
package main

import "fmt"

func reverse(numbers []int) []int {
	newNumbers := make([]int, 0, len(numbers))
	for i := len(numbers)-1; i >= 0; i-- {
		newNumbers = append(newNumbers, numbers[i])
	}
	return newNumbers
}

func main() {
	array := []int{1, 2, 3, 4, 5}

	fmt.Printf("%v\n", reverse(array))
	fmt.Printf("%v\n", array)
}
$ go run test_copy_simple.go
[5 4 3 2 1]
[1 2 3 4 5]