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 thenil
error value as printed byprintln
.
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("...")
}