Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In Golang, how can I sort a list of strings alphabetically without completely ignoring case?

I want the strings to be sorted alphabetically with control over whether "A" comes before "a".

In the Less() function using strings.ToLower() doesn't achieve this. Sometimes "A" comes before "a", and sometimes after.

like image 976
Koala3 Avatar asked Jan 29 '16 02:01

Koala3


2 Answers

instead of comparing the entire string using strings.ToLower, compare the individual runes.

https://play.golang.org/p/RUMlmrb7C3g

type ByCase []string

func (s ByCase) Len() int      { return len(s) }
func (s ByCase) Swap(i, j int) { s[i], s[j] = s[j], s[i] }

func (s ByCase) Less(i, j int) bool {
    iRunes := []rune(s[i])
    jRunes := []rune(s[j])

    max := len(iRunes)
    if max > len(jRunes) {
        max = len(jRunes)
    }

    for idx := 0; idx < max; idx++ {
        ir := iRunes[idx]
        jr := jRunes[idx]

        lir := unicode.ToLower(ir)
        ljr := unicode.ToLower(jr)

        if lir != ljr {
            return lir < ljr
        }

        // the lowercase runes are the same, so compare the original
        if ir != jr {
            return ir < jr
        }
    }

    // If the strings are the same up to the length of the shortest string, 
    // the shorter string comes first
    return len(iRunes) < len(jRunes)
}
like image 197
JimB Avatar answered Sep 21 '22 01:09

JimB


This may be a solution:

package main

import (
    "strings"
    "sort"
    "fmt"
)

var listOfStrings []string = []string{
    "mars bar",
    "milk-duds",
    "Mars bar",
    "milk",
    "milky-way",
    "Milk",
    "Milky-way",
    "mars",
}

type Alphabetic []string

func (list Alphabetic) Len() int { return len(list) }

func (list Alphabetic) Swap(i, j int) { list[i], list[j] = list[j], list[i] }

func (list Alphabetic) Less(i, j int) bool {
    var si string = list[i]
    var sj string = list[j]
    var si_lower = strings.ToLower(si)
    var sj_lower = strings.ToLower(sj)
    if si_lower == sj_lower {
        return si < sj
    }
    return si_lower < sj_lower
}

func main() {
    fmt.Println("UNSORTED")
    printStrings(listOfStrings)
    sort.Sort(Alphabetic(listOfStrings))
    fmt.Println()
    fmt.Println("SORTED ALPHABETICALLY")
    printStrings(listOfStrings)
}

func printStrings(slice []string) {
    for i := 0; i < len(slice); i++ {
        fmt.Println(slice[i])
    }
}

Here's the output:

UNSORTED
mars bar
milk-duds
Mars bar
milk
milky-way
Milk
Milky-way
mars

SORTED ALPHABETICALLY
mars
Mars bar
mars bar
Milk
milk
milk-duds
Milky-way
milky-way
like image 43
Koala3 Avatar answered Sep 20 '22 01:09

Koala3