MaPi
MaPi

Reputation: 1601

Golang byte vs string

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

Upvotes: 0

Views: 115

Answers (1)

mkopriva
mkopriva

Reputation: 38213

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 {
    second := map[rune]bool{}
    for _, r := range secondElements {
        second[r] = true
    }

    for _, r := range firstElements {
        if second[r] {
            fmt.Println(string(r))
            return string(r)
        }
    }

    panic("...")
}

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

Upvotes: 2

Related Questions