【问题标题】:How do I reverse an array in Go?如何在 Go 中反转数组?
【发布时间】:2013-10-08 05:02:16
【问题描述】:

http://play.golang.org/p/W70J4GU7nA

  s := []int{5, 2, 6, 3, 1, 4}
  sort.Reverse(sort.IntSlice(s))
  fmt.Println(s)
  // 5, 2, 6, 3, 1, 4

在 func Reverse(data Interface) Interface 中很难理解是什么意思。

如何反转数组?我不需要排序。

【问题讨论】:

标签: go


【解决方案1】:

老实说,这个很简单,我可以这样写:

package main

import "fmt"

func main() {

    s := []int{5, 2, 6, 3, 1, 4}

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

    fmt.Println(s)
}

http://play.golang.org/p/vkJg_D1yUb

(其他答案很好地解释了sort.Interface 以及如何使用它;所以我不会重复。)

【讨论】:

    【解决方案2】:

    通常,要对整数数组进行排序,请将它们包装在 IntSlice 中,它定义了方法 LenLessSwapsort.Sort 依次使用这些方法。 sort.Reverse 所做的是它采用定义 LenLessSwap 的现有类型,但它用一个始终与底层 Less 相反的新方法替换了 Less 方法:

    type reverse struct {
        // This embedded Interface permits Reverse to use the methods of
        // another Interface implementation.
        Interface
    }
    
    // Less returns the opposite of the embedded implementation's Less method.
    func (r reverse) Less(i, j int) bool {
        return r.Interface.Less(j, i)
    }
    
    // Reverse returns the reverse order for data.
    func Reverse(data Interface) Interface {
        return &reverse{data}
    }
    

    所以当你写sort.Reverse(sort.IntSlice(s)) 时,发生的事情是你得到了这个新的、“修改过的”IntSlice,它被Less 方法替换了。所以如果你在它上面调用sort.Sort,它调用Less,它将按降序排序。

    【讨论】:

      【解决方案3】:

      我迟到了 2 年,但只是为了好玩和感兴趣,我想贡献一个“古怪”的解决方案。

      假设任务确实是反转列表,那么对于原始性能bgp 的解决方案可能是无与伦比的。它通过前后交换数组项来简单有效地完成工作,这种操作在数组和切片的随机访问结构中非常有效。

      在函数式编程语言中,惯用的方法通常涉及递归。这在 Go 中看起来有点奇怪,并且性能会很差。也就是说,这是一个递归数组反转函数(在一个小测试程序中):

      package main
      
      import (
          "fmt"
      )
      
      func main() {
          myInts := []int{ 8, 6, 7, 5, 3, 0, 9 }
          fmt.Printf("Ints %v reversed: %v\n", myInts, reverseInts(myInts))
      }
      
      func reverseInts(input []int) []int {
          if len(input) == 0 {
              return input
          }
          return append(reverseInts(input[1:]), input[0]) 
      }
      

      输出:

      Ints [8 6 7 5 3 0 9] reversed: [9 0 3 5 7 6 8]
      

      再次强调,这是为了好玩,不是为了制作。不仅速度慢,而且如果列表太大,它会溢出堆栈。我刚刚测试过,它会反转一个 100 万 ints 的列表,但会在 1000 万时崩溃。

      【讨论】:

      【解决方案4】:

      首先,如果你想反转数组,这样做,

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

      然后,看看golang.org中Reverse的用法

      package main
      
      import (
          "fmt"
          "sort"
      )
      
      func main() {
          s := []int{5, 2, 6, 3, 1, 4} // unsorted
          sort.Sort(sort.Reverse(sort.IntSlice(s)))
          fmt.Println(s)
      }
      
      // output
      // [6 5 4 3 2 1]
      

      再看看Reverse and Sort的描述

      func Reverse(data Interface) Interface
      func Sort(data Interface)
      

      对数据进行排序。它对 data.Len 进行一次调用以确定 n,然后对 data.Less 和 data.Swap 进行 O(n*log(n)) 调用。排序不保证是稳定的。

      所以,如您所知,Sort 不仅仅是一种排序算法,您可以将其视为一个工厂,当您使用 Reverse 时,它​​只是返回一个反向排序算法,Sort 只是进行排序。

      【讨论】:

      【解决方案5】:

      这是一个更通用的切片反转函数。如果输入不是切片,它会恐慌。

      //panic if s is not a slice
      func ReverseSlice(s interface{}) {
          size := reflect.ValueOf(s).Len()
          swap := reflect.Swapper(s)
          for i, j := 0, size-1; i < j; i, j = i+1, j-1 {
              swap(i, j)
          }
      }
      

      【讨论】:

        【解决方案6】:

        如果你想反转数组,你可以以相反的顺序遍历它。由于语言中没有“反向范围”原语(至少现在还没有),你必须做这样的事情(http://play.golang.org/p/AhvAfMjs_7):

        s := []int{5, 2, 6, 3, 1, 4}
        for i := len(s) - 1; i >= 0; i-- {
            fmt.Print(s[i])
            if i > 0 {
                fmt.Print(", ")
            }
        }
        fmt.Println()
        

        关于sort.Reverse(data Interface) Interface的作用是否难以理解,我也是这么想的,直到看到“http://golang.org/src/pkg/sort/sort.go”的源代码。

        它只是使排序所需的比较“反过来”。

        【讨论】:

          【解决方案7】:

          这是另一种方法

          func main() {
              example := []int{1, 25, 3, 5, 4}
              sort.SliceStable(example, func(i, j int) bool {
                  return true
              })
              fmt.Println(example)
          }
          

          https://play.golang.org/p/-tIzPX2Ds9z

          【讨论】:

          • 我认为这不是正确的方法,我一直无法找到原因,但是下面的切片没有反转 []int{48,44,37,40,14, 45,8,38,12,31} 这有点奇怪。
          • @nJoshi 如果你使用sort.SliceStable,那么你的数组会被反转。答案应该更新为使用sort.SliceStable
          • 即使使用稳定排序我也无法理解的是,在相等条件的情况下不能保证顺序。 @nJoshi 提供的示例具有唯一的所有元素。这是来自 godoc : SliceStable 对提供的切片进行排序,给定提供的 less 函数,同时保持相等元素的原始顺序。
          • 我无法判断这是否错误。 play.golang.org/p/wNuwvvpdxMu
          【解决方案8】:

          这是一个简单的 Go 解决方案,它使用高效(无额外内存)方法来反转数组:

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

          这个想法是,颠倒一个数组相当于交换每个元素及其穿过中心的镜像。

          https://play.golang.org/p/kLFpom4LH0g

          【讨论】:

            【解决方案9】:
            func Reverse(data Interface) Interface
            

            这意味着它需要一个sort.Interface 并返回另一个sort.Interface——它本身实际上并没有进行任何排序。例如,如果您传入sort.IntSlice(本质上是一个[]int,可以传递给sort.Sort 以按升序对其进行排序),您将得到一个新的sort.Interface,它按降序对整数进行排序.

            顺便说一句,如果你点击the documentation中的函数名,它会直接链接到the sourceReverse。如您所见,它只是包装了您传入的sort.Interface,因此从Reverse 返回的值获取了原始sort.Interface 的所有方法。唯一不同的方法是Less 方法,它返回与嵌入式sort.Interface 上的Less 方法相反的方法。有关嵌入字段的详细信息,请参阅this part of the language spec

            【讨论】:

              【解决方案10】:

              来自Golang wiki SliceTricks

              用相同的元素替换切片的内容,但在 逆序:

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

              同样的事情,除了两个索引:

              for left, right := 0, len(a)-1; left < right; left, right = left+1, right-1 {
                a[left], a[right] = a[right], a[left]
              }
              

              【讨论】:

              • idk 为什么它被否决了。这对我很好。而且它比for i, j := 0, len(s)-1; i &lt; j; i, j = i+1, j-1 { 少了一些操作
              【解决方案11】:

              这是一个使用append的方法:

              package main
              import "fmt"
              
              func main() {
                 a := []int{10, 20, 30, 40, 50}
                 for n := len(a) - 2; n >= 0; n-- {
                    a = append(a[:n], append(a[n + 1:], a[n])...)
                 }
                 fmt.Println(a)
              }
              

              步骤图:

              10 20 30 40 50
              10 20 30    50 40
              10 20       50 40 30
              10          50 40 30 20
                          50 40 30 20 10
              

              【讨论】:

                【解决方案12】:

                要反转一个数组,迭代到它的中点,并用它的“镜像元素”交换每个元素:

                func main() {
                    xs := []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
                    itemCount := len(xs)
                    for i := 0; i < itemCount/2; i++ {
                        mirrorIdx := itemCount - i -1
                        xs[i], xs[mirrorIdx] = xs[mirrorIdx], xs[i]
                    }
                    fmt.Printf("xs: %v\n", xs)
                }
                

                https://play.golang.org/p/JeSApt80_k

                【讨论】:

                  【解决方案13】:

                  此答案主要针对希望在 for 循环中仅使用一个变量而不是使用两个变量(如 i 和 j)来编写此代码的初学者。

                  package main
                  
                  import "fmt"
                  
                  func main() {
                  array := []int{45, 17, 43, 67, 21, 4, 97, 44, 54, 98, 665}
                  fmt.Println("initial array:", array)
                  loop_iteration := len(array)
                  if len(array)%2 == 0 {
                      loop_iteration = (len(array) / 2) - 1
                    } else {
                      loop_iteration = int(len(array) / 2)  //This will give the lower integer value of that float number.
                      }
                  for i := 0; i <= loop_iteration; i++ {
                      array[i], array[(len(array)-1)-i] = array[(len(array)-1)-i], array[i]
                      }
                  fmt.Println("reverse array:", array)
                  }
                  

                  【讨论】:

                    【解决方案14】:

                    这是我的solution

                    package main
                    
                    import (
                    	"fmt"
                    )
                    
                    func main() {
                    	var numbers = [10]int {1,2,3,4,5,6,7,8,9,10}
                    	var reverseNumbers [10]int
                    	j:=0
                    	for i:=len(numbers)-1; i>=0 ; i-- {
                    		reverseNumbers[j]=numbers[i]
                    		j++	
                    	}
                    	fmt.Println(reverseNumbers)
                    }

                    【讨论】:

                      【解决方案15】:

                      这是我反转数组的解决方案:

                      func reverse_array(array []string) []string {
                          lenx := len(array) // lenx holds the original array length
                          reversed_array := make([]string, lenx) // creates a slice that refer to a new array of length lenx
                      
                          for i := 0; i < lenx; i++ {
                              j := lenx - (i + 1) // j initially holds (lenx - 1) and decreases to 0 while i initially holds 0 and increase to (lenx - 1)
                              reversed_array[i] = array[j]
                          }
                      
                          return reversed_array
                      }
                      

                      您可以在 go playground the go playground

                      上尝试此解决方案
                      package main
                      
                      import "fmt"
                      
                      func main() {
                          array := []string{"a", "b", "c", "d"}
                      
                          fmt.Println(reverse_array(array)) // prints [d c b a]
                      }
                      

                      【讨论】:

                        【解决方案16】:

                        不要颠倒它,让它保持现在,然后向后迭代。

                        【讨论】:

                        • 当然可以。但它更快,而不是反转它,只是向后迭代。
                        • 如果你将切片传递给向前迭代的东西怎么办?有时你必须扭转局面。
                        • 然后反转它:-)
                        猜你喜欢
                        • 1970-01-01
                        • 2012-04-08
                        • 1970-01-01
                        • 1970-01-01
                        • 2020-01-04
                        • 2020-08-06
                        • 2014-01-16
                        • 1970-01-01
                        • 2023-03-22
                        相关资源
                        最近更新 更多