Home > other >  Golang byte vs string
Golang byte vs string

Time:12-04

I'm trying to find a common element between two strings of equal length in Golang.

The element is found, but the string representation seems to include the byte value too. How can I get rid of it?

func main() {
    println(fmt.Printf("common element = %s",
        findCommonElement("abcdefghi", "ijklmnopq")))
}

func findCommonElement(firstElements, secondElements string) string {
    elementsInFirstGroup := make(map[string]bool)
    for _, charValue := range firstElements {
        elementsInFirstGroup[string(charValue)] = true
    }
    for index := range firstElements {
        if _, ok := elementsInFirstGroup[string(secondElements[index])]; ok {
            matchingElem := secondElements[index]
            println(string(matchingElem))
            return string(matchingElem)
        }
    }

    panicMessage := fmt.Sprintf("Could not find a common item between %s and %s", firstElements, secondElements)
    panic(panicMessage)
}

The output I get is

i
common element = i18 (0x0,0x0)

Code available here

CodePudding user response:

You should use fmt.Sprintf instead of fmt.Printf.

And avoid using the builtin println, instead use fmt.Println.


https://pkg.go.dev/[email protected]#Printf

func Printf(format string, a ...any) (n int, err error)

Printf formats according to a format specifier and writes to standard output. It returns the number of bytes written and any write error encountered.

Hence the 18 (0x0,0x0)...

  • 18 is the number of characters in the string "common element = i".
  • (0x0,0x0) is the nil error value as printed by println.

More importantly however, your algorithm is flawed because it is mixing up bytes with runes. When you range over a string, the iteration variable charValue will be assigned a rune, which may be multi-byte. However when you index a string (e.g., secondElements[index]) the result of that is always a single byte. So panics or gibberish (invalid bytes) will inevitably be the result of your function. See example.

You may get better results doing something like the following:

func findCommonElement(firstElements, secondElements string) string {
    visited := map[rune]bool{}
    for _, r1 := range firstElements {
        if !visited[r1] {
            visited[r1] = true
        } else {
            continue // go to next rune in string
        }

        for _, r2 := range secondElements {
            if r1 == r2 {
                fmt.Println(string(r1))
                return string(r1)
            }
        }
    }

    panic("...")
}

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

  •  Tags:  
  • go
  • Related