How do I reverse a slice in go?

huangapple go评论89阅读模式
英文:

How do I reverse a slice in go?

问题

如何在Go语言中反转一个任意切片([]interface{})?我不想编写LessSwap来使用sort.Reverse。是否有一种简单的内置方法来实现这个功能?

英文:

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?

答案1

得分: 107

在Go 1.21或更高版本中使用slices.Reverse

slices.Reverse(s)

Go版本1.20及更早版本的答案:

标准库中没有用于反转切片的内置函数。使用for循环来反转切片:

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

在Go 1.18或更高版本中使用类型参数编写通用的反转函数:

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

在Go版本1.8或更高版本中使用reflect.Swapper编写适用于任意切片类型的函数:

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

本答案中的函数会原地反转切片。如果不想修改原始切片,在反转切片之前复制切片

英文:

Use slices.Reverse in Go 1.21 or later:

slices.Reverse(s)

Answers for Go version 1.20 and earlier:

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 &lt; 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 &lt; 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 &lt; j; i, j = i+1, j-1 {
		swap(i, j)
	}
}

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.

答案2

得分: 10

这是另一种可能的反转通用切片的方法(适用于Go 1.18):

// 你可以编辑这段代码!
// 点击这里开始输入。
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
	})
}

运行上面的程序应该输出:

[-1 100 1 20 15 5 10]
[world hello]
d l r o w o l l e h 
程序已退出。

go playground

英文:

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 (
	&quot;fmt&quot;
	&quot;sort&quot;
)

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

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

	runes := []rune{&#39;h&#39;, &#39;e&#39;, &#39;l&#39;, &#39;l&#39;, &#39;o&#39;, &#39;w&#39;, &#39;o&#39;, &#39;r&#39;, &#39;l&#39;, &#39;d&#39;}
	ReverseSlice(runes)
	for _, r := range runes {
		fmt.Print(string(r), &quot; &quot;)
	}
}

func ReverseSlice[T comparable](s []T) {
	sort.SliceStable(s, func(i, j int) bool {
		return i &gt; 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.

<kbd>go playground</kbd>

答案3

得分: 7

这将返回一个反转的切片,而不会修改原始切片。

算法使用了官方维基页面上的方法: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
}
英文:

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 &gt;= 0; i-- {
opp := len(a) - 1 - i
a[i], a[opp] = a[opp], a[i]
}
return a
}

答案4

得分: 1

以下是您要翻译的内容:

这是我的代码示例,您可以在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)
}

英文:

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

package main

import (
	&quot;fmt&quot;
	&quot;reflect&quot;
	&quot;errors&quot;
)

func ReverseSlice(data interface{}) {
	value := reflect.ValueOf(data)
	if value.Kind() != reflect.Slice {
		panic(errors.New(&quot;data must be a slice type&quot;))
	}
	valueLen := value.Len()
	for i := 0; i &lt;= 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{&quot;bob&quot;, &quot;mary&quot;, &quot;sally&quot;, &quot;michael&quot;}
	ReverseSlice(names)
	fmt.Println(names)
}

答案5

得分: 1

这是我正在使用的带有泛型(go 1.18+)的函数。你可以使用它来反转任何类型的切片,甚至是字符串(使用拆分/连接的技巧)。它不会改变原始切片。

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

更好的Go Playground:链接

英文:

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 (
	&quot;fmt&quot;
	&quot;strings&quot;
)

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

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

	return
}

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

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

	c := &quot;abc&quot;
	fmt.Println(c, strings.Join(Reverse(strings.Split(c, &quot;&quot;)), &quot;&quot;))
}

Better Go Playground

答案6

得分: 0

这个通用的切片反转函数可以帮助你:

func ReverseSlice[T comparable](s []T) []T {
    var r []T
    for i := len(s) - 1; i >= 0; i-- {
        r = append(r, s[i])
    }
    return r
}

这个函数可以将给定的切片进行反转。

英文:

This generic slice reversal function should do it for you:

func ReverseSlice[T comparable](s []T) []T {
var r []T
for i := len(s) - 1; i &gt;= 0; i-- {
r = append(r, s[i])
}
return r
}

答案7

得分: 0

func Reverse[T any](array []T) []T {
	length := len(array)
	result := make([]T, length)
	for i, elem := range array {
		result[length-1-i] = elem
	}
	return result
}

func ReverseInPlace[T any](array []T) []T {
	length := len(array)
	swap := reflect.Swapper(array)
	for i := 0; i < length/2; i++ {
		swap(i, length-1-i)
	}
	return array
}

增强了接受的答案。

并进行了测试:

func TestReverse(t *testing.T) {
	t.Run("空数组", func(t *testing.T) {
		input := []int{}
		assert.Equal(t, []int{}, Reverse(input))
		assert.Equal(t, []int{}, input)
	})

	t.Run("反转整数", func(t *testing.T) {
		input := []int{1, 2, 3}
		assert.Equal(t, []int{3, 2, 1}, Reverse(input))
		assert.Equal(t, []int{1, 2, 3}, input)
	})

	t.Run("反转字符串", func(t *testing.T) {
		input := []string{"a", "b", "c"}
		assert.Equal(t, []string{"c", "b", "a"}, Reverse(input))
		assert.Equal(t, []string{"a", "b", "c"}, input)
	})
}

func TestReverseInPlace(t *testing.T) {
	t.Run("空数组", func(t *testing.T) {
		input := []int{}
		assert.Equal(t, []int{}, ReverseInPlace(input))
		assert.Equal(t, []int{}, input)
	})

	t.Run("反转整数", func(t *testing.T) {
		input := []int{1, 2, 3}
		assert.Equal(t, []int{3, 2, 1}, ReverseInPlace(input))
		assert.Equal(t, []int{3, 2, 1}, input)
	})

	t.Run("反转字符串", func(t *testing.T) {
		input := []string{"a", "b", "c"}
		assert.Equal(t, []string{"c", "b", "a"}, ReverseInPlace(input))
		assert.Equal(t, []string{"c", "b", "a"}, input)
	})
}
英文:
func Reverse[T any](array []T) []T {
	length := len(array)
	result := make([]T, length)
	for i, elem := range array {
		result[length-1-i] = elem
	}
	return result
}

func ReverseInPlace[T any](array []T) []T {
	length := len(array)
	swap := reflect.Swapper(array)
	for i := 0; i &lt; length/2; i++ {
		swap(i, length-1-i)
	}
	return array
}

Enhanced the accepted answer.

And tests:

func TestReverse(t *testing.T) {
	t.Run(&quot;Empty array&quot;, func(t *testing.T) {
		input := []int{}
		assert.Equal(t, []int{}, Reverse(input))
		assert.Equal(t, []int{}, input)
	})

	t.Run(&quot;Reverse integers&quot;, func(t *testing.T) {
		input := []int{1, 2, 3}
		assert.Equal(t, []int{3, 2, 1}, Reverse(input))
		assert.Equal(t, []int{1, 2, 3}, input)
	})

	t.Run(&quot;Reverse strings&quot;, func(t *testing.T) {
		input := []string{&quot;a&quot;, &quot;b&quot;, &quot;c&quot;}
		assert.Equal(t, []string{&quot;c&quot;, &quot;b&quot;, &quot;a&quot;}, Reverse(input))
		assert.Equal(t, []string{&quot;a&quot;, &quot;b&quot;, &quot;c&quot;}, input)
	})
}

func TestReverseInPlace(t *testing.T) {
	t.Run(&quot;Empty array&quot;, func(t *testing.T) {
		input := []int{}
		assert.Equal(t, []int{}, ReverseInPlace(input))
		assert.Equal(t, []int{}, input)
	})

	t.Run(&quot;Reverse integers&quot;, func(t *testing.T) {
		input := []int{1, 2, 3}
		assert.Equal(t, []int{3, 2, 1}, ReverseInPlace(input))
		assert.Equal(t, []int{3, 2, 1}, input)
	})

	t.Run(&quot;Reverse strings&quot;, func(t *testing.T) {
		input := []string{&quot;a&quot;, &quot;b&quot;, &quot;c&quot;}
		assert.Equal(t, []string{&quot;c&quot;, &quot;b&quot;, &quot;a&quot;}, ReverseInPlace(input))
		assert.Equal(t, []string{&quot;c&quot;, &quot;b&quot;, &quot;a&quot;}, input)
	})
}

huangapple
  • 本文由 发表于 2015年1月21日 09:47:23
  • 转载请务必保留本文链接:https://go.coder-hub.com/28058278.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定