在Go语言中高效地进行数字(字符串类型)的逆向索引。

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

Efficient reverse indexing of number (type string) in Go

问题

背景:给定一个字符串s,其中s是任意正整数,将其顺序反转,并将每个数字乘以它的新索引(+1)后求和。

例如,对于字符串"98765",返回的值将是:(1x5) + (2x6) + (3x7) + (4x8) + (5x9) = 115

你可以在这里找到我目前的工作解决方案:Go playground。我想知道是否有更好的方法来完成这个任务,无论是在可读性还是效率方面。例如,我决定使用count变量而不是使用ilen,因为它似乎更清晰。我对int/string转换也不太熟悉,但我假设需要使用strconv

func reverseStringSum(s string) int {
	total := 0
	count := 1
	for i := len(s) - 1; i >= 0; i-- {
		char := string([]rune(s)[i])
		num, _ := strconv.Atoi(char)
		total += count * num
		count++
	}
	return total
}
英文:

Background

TLDR (and simplified): Given a string s, where s is any positive integer, reverse the order and summate each digit multiplied by it's new index (+1).

For example, the value returned from "98765" would be: (1x5) + (2x6) + (3x7) + (4x8) + (5*9)= 115.

My current working solution can be found here: Go playground. I'd like to know whether there's a better way of doing this, be it readability or efficiency. For example, I decided in favour of a count variable instead utilising i and len as it seemed clearer. I'm also not very familiar with int/string conversions but I'm assuming making use of strconv is required.

func reverseStringSum(s string) int {
	total := 0
	count := 1
	for i := len(s) - 1; i >= 0; i-- {
		char := string([]rune(s)[i])
		num, _ := strconv.Atoi(char)
		total += count * num
		count++
	}
	return total
}

答案1

得分: 5

这是解决完整问题的高效方法:sum("987-65") = 115。完整的问题在你的工作解决方案链接中有记录:https://go.dev/play/p/DJ1ZYYDFnfq。

package main

import "fmt"

func reverseSum(s string) int {
    sum := 0
    for i, j := len(s)-1, 0; i >= 0; i-- {
        d := int(s[i]) - '0'
        if 0 <= d && d <= 9 {
            j++
            sum += j * d
        }
    }
    return sum
}

func main() {
    s := "987-65"
    sum := reverseSum(s)
    fmt.Println(sum)
}

https://go.dev/play/p/bx7wfmtXaie

115

由于我们正在讨论高效的Go代码,我们需要一些Go基准测试。

$ go test reversesum_test.go -bench=. -benchmem

BenchmarkSumTBJ-8     4001182   295.8 ns/op     52 B/op   6 allocs/op
BenchmarkSumA2Q-8   225781720     5.284 ns/op    0 B/op   0 allocs/op

你的解决方案(TBJ)很慢。

reversesum_test.go:

package main

import (
    "strconv"
    "strings"
    "testing"
)

func reverseSumTBJ(s string) int {
    total := 0
    count := 1
    for i := len(s) - 1; i >= 0; i-- {
        char := string([]rune(s)[i])
        num, _ := strconv.Atoi(char)
        total += count * num
        count++
    }
    return total
}

func BenchmarkSumTBJ(b *testing.B) {
    for n := 0; n < b.N; n++ {
        rawString := "987-65"
        stringSlice := strings.Split(rawString, "-")
        numberString := stringSlice[0] + stringSlice[1]
        reverseSumTBJ(numberString)
    }
}

func reverseSumA2Q(s string) int {
    sum := 0
    for i, j := len(s)-1, 0; i >= 0; i-- {
        d := int(s[i]) - '0'
        if 0 <= d && d <= 9 {
            j++
            sum += j * d
        }
    }
    return sum
}

func BenchmarkSumA2Q(b *testing.B) {
    for n := 0; n < b.N; n++ {
        rawString := "987-65"
        reverseSumA2Q(rawString)
    }
}

反向求和是一个更大问题的一部分,用于计算CAS注册号的校验位。

package main

import "fmt"

// CASRNCheckDigit返回计算的CAS注册号校验位。
func CASRNCheckDigit(s string) string {
    // CAS注册号
    // https://en.wikipedia.org/wiki/CAS_Registry_Number
    //
    // 校验位通过将最后一位乘以1,
    // 前一位乘以2,前一位乘以3等,
    // 将所有这些相加并计算模10的和来找到。
    //
    // 水的CAS号是7732-18-5:
    // 校验和5计算为
    // (8×1 + 1×2 + 2×3 + 3×4 + 7×5 + 7×6)
    // = 105; 105 mod 10 = 5。
    //
    // CAS注册号的校验位验证
    // https://www.cas.org/support/documentation/chemical-substances/checkdig

    for i, sep := 0, 0; i < len(s); i++ {
        if s[i] == '-' {
            sep++
            if sep == 2 {
                s = s[:i]
                break
            }
        }
    }

    sum := 0
    for i, j := len(s)-1, 0; i >= 0; i-- {
        d := int(s[i]) - '0'
        if 0 <= d && d <= 9 {
            j++
            sum += j * d
        }
    }
    return string(rune(sum%10 + '0'))
}

func main() {
    var rn, cd string
    // 987-65-5: Adenosine 5'-triphosphate disodium salt
    // https://www.chemicalbook.com/CASEN_987-65-5.htm
    rn = "987-65"
    cd = CASRNCheckDigit(rn)
    fmt.Println("CD:", cd, "\tRN:", rn)
    // 732-18-5: Water
    // https://www.chemicalbook.com/CASEN_7732-18-5.htm
    rn = "7732-18-5"
    cd = CASRNCheckDigit(rn)
    fmt.Println("CD:", cd, "\tRN:", rn)
    // 7440-21-3: Silicon
    // https://www.chemicalbook.com/CASEN_7440-21-3.htm
    rn = "7440-21-3"
    cd = CASRNCheckDigit(rn)
    fmt.Println("CD:", cd, "\tRN:", rn)
}

https://go.dev/play/p/VYh-5LuGpCn

BenchmarkCD-4   37187641   30.29 ns/op   4 B/op   1 allocs/op
英文:

Here's an efficient way to solve the complete problem: sum(&quot;987-65&quot;) = 115. The complete problem is documented in your working solution link: https://go.dev/play/p/DJ1ZYYDFnfq.

package main
import &quot;fmt&quot;
func reverseSum(s string) int {
sum := 0
for i, j := len(s)-1, 0; i &gt;= 0; i-- {
d := int(s[i]) - &#39;0&#39;
if 0 &lt;= d &amp;&amp; d &lt;= 9 {
j++
sum += j * d
}
}
return sum
}
func main() {
s := &quot;987-65&quot;
sum := reverseSum(s)
fmt.Println(sum)
}

https://go.dev/play/p/bx7wfmtXaie

115

Since we are talkng about efficient Go code, we need some Go benchmarks.

$ go test reversesum_test.go -bench=. -benchmem

BenchmarkSumTBJ-8     4001182   295.8 ns/op     52 B/op   6 allocs/op
BenchmarkSumA2Q-8   225781720     5.284 ns/op    0 B/op   0 allocs/op

Your solution (TBJ) is slow.

reversesum_test.go:

package main
import (
&quot;strconv&quot;
&quot;strings&quot;
&quot;testing&quot;
)
func reverseSumTBJ(s string) int {
total := 0
count := 1
for i := len(s) - 1; i &gt;= 0; i-- {
char := string([]rune(s)[i])
num, _ := strconv.Atoi(char)
total += count * num
count++
}
return total
}
func BenchmarkSumTBJ(b *testing.B) {
for n := 0; n &lt; b.N; n++ {
rawString := &quot;987-65&quot;
stringSlice := strings.Split(rawString, &quot;-&quot;)
numberString := stringSlice[0] + stringSlice[1]
reverseSumTBJ(numberString)
}
}
func reverseSumA2Q(s string) int {
sum := 0
for i, j := len(s)-1, 0; i &gt;= 0; i-- {
d := int(s[i]) - &#39;0&#39;
if 0 &lt;= d &amp;&amp; d &lt;= 9 {
j++
sum += j * d
}
}
return sum
}
func BenchmarkSumA2Q(b *testing.B) {
for n := 0; n &lt; b.N; n++ {
rawString := &quot;987-65&quot;
reverseSumA2Q(rawString)
}
}

The reverse sum is part of a larger problem, computing a CAS Registry Number check digit.

package main
import &quot;fmt&quot;
// CASRNCheckDigit returns the computed
// CAS Registry Number check digit.
func CASRNCheckDigit(s string) string {
// CAS Registry Number
// https://en.wikipedia.org/wiki/CAS_Registry_Number
//
// The check digit is found by taking the last digit times 1,
// the preceding digit times 2, the preceding digit times 3 etc.,
// adding all these up and computing the sum modulo 10.
//
// The CAS number of water is 7732-18-5:
// the checksum 5 is calculated as
// (8&#215;1 + 1&#215;2 + 2&#215;3 + 3&#215;4 + 7&#215;5 + 7&#215;6)
// = 105; 105 mod 10 = 5.
//
// Check Digit Verification of CAS Registry Numbers
// https://www.cas.org/support/documentation/chemical-substances/checkdig
for i, sep := 0, 0; i &lt; len(s); i++ {
if s[i] == &#39;-&#39; {
sep++
if sep == 2 {
s = s[:i]
break
}
}
}
sum := 0
for i, j := len(s)-1, 0; i &gt;= 0; i-- {
d := int(s[i]) - &#39;0&#39;
if 0 &lt;= d &amp;&amp; d &lt;= 9 {
j++
sum += j * d
}
}
return string(rune(sum%10 + &#39;0&#39;))
}
func main() {
var rn, cd string
// 987-65-5: Adenosine 5&#39;-triphosphate disodium salt
// https://www.chemicalbook.com/CASEN_987-65-5.htm
rn = &quot;987-65&quot;
cd = CASRNCheckDigit(rn)
fmt.Println(&quot;CD:&quot;, cd, &quot;\tRN:&quot;, rn)
// 732-18-5: Water
// https://www.chemicalbook.com/CASEN_7732-18-5.htm
rn = &quot;7732-18-5&quot;
cd = CASRNCheckDigit(rn)
fmt.Println(&quot;CD:&quot;, cd, &quot;\tRN:&quot;, rn)
// 7440-21-3: Silicon
// https://www.chemicalbook.com/CASEN_7440-21-3.htm
rn = &quot;7440-21-3&quot;
cd = CASRNCheckDigit(rn)
fmt.Println(&quot;CD:&quot;, cd, &quot;\tRN:&quot;, rn)
}

https://go.dev/play/p/VYh-5LuGpCn

BenchmarkCD-4   37187641   30.29 ns/op   4 B/op   1 allocs/op

答案2

得分: 0

也许这样更有效率:

func reverseStringSum(s string) int {
    total := 0
    count := 1
    for i := len(s) - 1; i >= 0; i-- {
        num, _ := strconv.Atoi(string(s[i]))
        total += count * num
        count++
    }
    return total
}

这段代码的功能是将输入的字符串逆序处理,并计算每个字符与其在字符串中的位置的乘积之和。最后返回计算结果。

英文:

Maybe this is more efficient

func reverseStringSum(s string) int {
total := 0
count := 1
for i := len(s) - 1; i &gt;= 0; i-- {
num, _ := strconv.Atoi(string(s[i]))
total += count * num
count++
}
return total
}

huangapple
  • 本文由 发表于 2021年12月8日 07:49:36
  • 转载请务必保留本文链接:https://go.coder-hub.com/70268326.html
匿名

发表评论

匿名网友

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

确定