DEV Community

Cover image for An efficient way to compare strings in Go
Rakesh Mothukuri
Rakesh Mothukuri

Posted on • Originally published at rakeshmothukuri.dev

An efficient way to compare strings in Go

Introduction

One of the most overlooked operations is comparing two strings and this might not cause system overhead but definitely, it is a good practice to write an efficient code where possible. These small dividends definitely pay at the end when the application is under real stress in production.

Note: I am amateur in Go if you are an experienced professional in Go and find anything wrong here don't be annoyed. If you could point the mistake I will correct those accordingly.

One of the often used string comparisons is

strings.ToLower(stringA) == strings.ToLower(stringB)

but this way of comparing takes a lot of time per operation and the reason is, In Go, a string is an immutable sequence of runes. rune in Go is an integer value represents code point

The more detailed and sensible explanation is given by Rob Pike in blog: https://blog.golang.org/strings Its a very nice bedtime read which gives a recap of basics of strings in programming languages.

Here ToLower a standard function in strings package which when used traverse through the entire string converts it to a lower case and returns a new string cause strings in Go is immutable which means strings.ToLower allocates new memory spaces for these two strings.

sample code:

func CompareStringsInCrudeWay(stringA, stringB string) (bool, error) {
    if strings.ToLower(stringA) == strings.ToLower(stringB) {
        return true, nil
    } else {
        return false, nil
    }
}

Benchmark:

Input:

  stringA = "rakesh123456789mothukuri123456789"

  stringB = "ramesh123456789mothukuri123456789"

BenchmarkCompare-8       8304722               151 ns/op               0 B/op          0 allocs/op

If we notice in earlier benchmark figures this operation takes 151 nanoseconds per operation. But is this too much we need to talk about? No, but if there is a simple change to way strings are compared and we could get this down to 30 nanoseconds why not?

Optimization

To optimize we could find a way instead traverse through runes of each string, compare each character in the string, if rune doesn't match we would convert rune to lowercase and compare again and if they still don't match we break the loop and break the loop and return strings are not same. This process will save operation time spent comparing string.

Pseudocode

func Compare(stringA, stringB string) bool {
    for i := 0; i < len(stringA); i++ {
        if stringA[i] == stringB[i] {
            continue
        }
        if unicode.ToLower(stringA[i]) != unicode.ToLower(stringB[i]) {
            return false
        }
    }
    return true
}

But this has more logic here to remember and implement every time we compare string only if there is an easy way to do. Go strings package has a method which performs in this fashion which is strings.EqualFold

sample code using EqualFold

func CompareStringsInEfficientWay(stringA, stringB string) (bool, error) {
   if strings.EqualFold(stringA, stringB) {
      return true, nil
   } else {
      return false, nil
   }
}

Benchmark:

Input:
  stringA = "rakesh123456789mothukuri123456789"
  stringB = "ramesh123456789mothukuri123456789"
BenchmarkCompare-8      76842292                17.1 ns/op             0 B/op          0 allocs/op

Now, it took 17 nanoseconds per operation, These small wins over a period of time will definitely payback, not only they pay back it also helps promote an efficient way of writing code.

This is the end of the blog if you think there is a more efficient way of comparing string in Go please drop me a message I will attribute you and amend the content.

Top comments (2)

Collapse
 
freedom profile image
Freedom
Collapse
 
rockey5520 profile image
Rakesh Mothukuri

Yes, @freedom Brett Jones who wrote answer for that is my inspiration to write one of my version.