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:
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:
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:
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:
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:
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]