How one can do case insensitive sorting using sort.Strings() in Golang?

Issue

Is there any way to pass the custom function in the sort.Strings() to do the case-insensitive sorting on the list of strings?

data := []string{"A", "b", "D", "c"}

The output should be: A, b, c, D

The equivalent of the above requirement in Python is like :

li = sorted(data, key=lambda s: s.lower())

Do we have something like that in golang?

Solution

The translation of the Python code to Go is:

sort.Slice(data, func(i, j int) bool { return strings.ToLower(data[i]) < strings.ToLower(data[j]) })

Run it on the Go Playground.

This approach, like the Python code in the question, can allocate two strings for each comparison. The allocations are probably OK for the example in the question, but can be a problem in other scenarios.

To avoid allocations, compare the strings rune by rune:

func lessLower(sa, sb string) bool {
    for {
        rb, nb := utf8.DecodeRuneInString(sb)
        if nb == 0 {
            // The number of runes in sa is greater than or 
            // equal to the number of runes in sb. It follows
            // that sa is not less than sb.
            return false
        }

        ra, na := utf8.DecodeRuneInString(sa)
        if na == 0 {
            // The number of runes in sa is less than the
            // number of runes in sb. It follows that sa
            // is less than sb.
            return true
        }

        rb = unicode.ToLower(rb)
        ra = unicode.ToLower(ra)

        if ra != rb {
            return ra < rb
        }

        // Trim rune from the beginning of each string.
        sa = sa[na:]
        sb = sb[nb:]
    }
}
⋮
sort.Slice(data, func(i, j int) bool { return lessLower(data[i], data[j]) })

Run it on the Go Playground.

Take a look at the collate package if you need to sort by language or culture specific sort orders.

Answered By – Bayta Darell

Answer Checked By – Marilyn (GoLangFix Volunteer)

Leave a Reply

Your email address will not be published.