【问题标题】:How to convert a number to string, of the form 1=A1, 2=A2, ... 9=B1, ... 64=H8 in Golang?如何在 Golang 中将数字转换为字符串,格式为 1=A1, 2=A2, ... 9=B1, ... 64=H8?
【发布时间】:2016-08-11 09:18:11
【问题描述】:

此代码为A1..A9, B0..B9, C0..C9, ...

但我只想要A1..A8, B1..B8, C1..C8, D1..D8, E1..E8, F1..F8, G1..G8, H1..H8 (1-64)。

package main

import (
    "fmt"
)

func ToString(n int8) string {

    return string((n/10)+65) + string(((n%10)+49)-1)

}

func main() {
    var i int8
    for i = 1; i < 11; i++ {
        fmt.Println(ToString(i))
    }
}

【问题讨论】:

    标签: string go char int chess


    【解决方案1】:

    首先,您除以错误的数字。如果您只希望数字最多为 8,则需要除以 8。

    其次,您不需要在第二个字符串中减一,但您确实需要减少 n

    func ToString(n int8) string {
        n--
        return string((n/8)+65) + string((n%8)+49)
    }
    
    func main() {
        var i int8
        for i = 1; i <= 64; i++ {
            fmt.Println(ToString(i))
        }
    }
    

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

    【讨论】:

      【解决方案2】:

      让我们看看不同的方法和性能改进。

      所有解决方案和基准测试代码都可以在Go Playground 上找到。 Playground 上的代码是测试文件,而不是可执行文件。您必须将其保存到名为 XX_test.go 的文件中并使用 go test -bench . 运行它。

      字符串连接

      Ainar-G 的回答很酷 (+1):

      func ToStringConcat(n byte) string {
          n--
          return string((n/8)+65) + string((n%8)+49)
      }
      

      字节切片

      但请注意,前面的解决方案连接了 2 个 string 值,这是“昂贵的”,特别是如果我们想多次调用此 ToString()

      如果我们尝试转换包含 2 个代码(第一个左移 8 位)的单个整数,可能会认为我们可以省去 string 连接,但这不会像转换整数到string 会产生一个string 值和一个rune(一个string 包含整数的UTF-8 表示)。

      但是我们可以使用一个[]byte有2个值(字母代码和数字代码),然后我们只需要将convert这个单片值转换为string

      func ToStringSlice(n byte) string {
          n--
          return string([]byte{(n / 8) + 65, (n % 8) + 49})
      }
      

      字符串常量和切片

      string 的值在 Go 中是 slicable,这会产生一个新的 string(新的 string 标头)。因此,我们可以使用所有值的string 常量,并进行简单的切片以获得我们需要的部分:

      const values = "  A1A2A3A4A5A6A7A8B1B2B3B4B5B6B7B8C1C2C3C4C5C6C7C8D1D2D3D4D5D6D7D8E1E2E3E4E5E6E7E8F1F2F3F4F5F6F7F8G1G2G3G4G5G6G7G8H1H2H3H4H5H6H7H8"
      
      func ToStringConst(n byte) string {
          n *= 2
          return values[n : n+2]
      }
      

      字典

      即使对string 进行切片会产生一个共享底层数组的子字符串,但仍需要创建一个新的string 标头。

      由于我们没有很多可能的值,因此最好(最快)的解决方案是准备所有可能的值,然后进行简单的查找。由于输入的是数字,我们甚至不需要map,我们可以使用一个简单的[]string切片:

      var dict = []string{"",
          "A1", "A2", "A3", "A4", "A5", "A6", "A7", "A8",
          "B1", "B2", "B3", "B4", "B5", "B6", "B7", "B8",
          "C1", "C2", "C3", "C4", "C5", "C6", "C7", "C8",
          "D1", "D2", "D3", "D4", "D5", "D6", "D7", "D8",
          "E1", "E2", "E3", "E4", "E5", "E6", "E7", "E8",
          "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8",
          "G1", "G2", "G3", "G4", "G5", "G6", "G7", "G8",
          "H1", "H2", "H3", "H4", "H5", "H6", "H7", "H8",
      }
      
      func ToStringDict(n byte) string {
          return dict[n]
      }
      

      速度分析(基准)

      让我们对上述解决方案的速度进行基准测试:

      func BenchmarkConcat(b *testing.B) {
          for i := 0; i < b.N; i++ { ToStringConcat(1) }
      }
      
      func BenchmarkSlice(b *testing.B) {
          for i := 0; i < b.N; i++ { ToStringSlice(1) }
      }
      
      func BenchmarkConst(b *testing.B) {
          for i := 0; i < b.N; i++ { ToStringConst(1) }
      }
      
      func BenchmarkDict(b *testing.B) {
          for i := 0; i < b.N; i++ { ToStringDict(1) }
      }
      

      结果:

      BenchmarkConcat-4       20000000               106 ns/op
      BenchmarkSlice-4        100000000               17.0 ns/op
      BenchmarkConst-4        2000000000               1.34 ns/op
      BenchmarkDict-4         2000000000               1.04 ns/op
      

      只要从串联跳到切片转换,就立马变6倍

      利用字符串切片,我们再次将其 快了 12 倍

      预先构建所有可能的值并进行简单的查找,我们进一步获得了 22%

      比较最终与初始:字典查找比原始连接快一百倍

      使用fmt

      为了完整起见,这里是使用fmt 包的解决方案:

      func ToStringFmt(n byte) string {
          n--
          return fmt.Sprintf("%c%c", (n/8)+65, (n%8)+49)
      }
      

      但是这个比我们最慢的字符串连接解决方​​案慢了将近 2.5 倍,因为它必须将参数包装到 interface{} 值中,创建并将它们放入一个切片中(对于 vararg),必须解析和分析string 格式,使用反射处理参数,在缓冲区中构建 string 表示,最终用于生成返回的 string 值。很多事情发生在“一般”情况下,而我们的“特殊”情况不需要。

      【讨论】:

      • 我一直对您在回答中所付出的彻底性和努力感到惊讶。你应该写一本书。
      • @Ainar-G 它的标题是什么?
      • 如果是一本教程书,“Gopher's First Go”听起来不错。
      猜你喜欢
      • 1970-01-01
      • 2019-06-05
      • 2016-01-02
      • 1970-01-01
      • 2017-08-18
      • 2015-10-07
      • 2017-04-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多