Golang : Sort words with first uppercase letter




Problem:

You use the sort.Strings() function to sort a slice of words. However, you noticed that words with the first letter in uppercase are not sorted as advertised. For example:

Before: HEre is an Example of how to convert

After: Example HEre a an and convert

The word HEre and Example are not sorted and place in front of the sorted list. Is this a bug or feature? Not sure.

So, how to get the words with first upper case letter sorted?

Solution:

The following code still uses the sort.Strings() function. However, before sorting... it will first build a map of words that start with first uppercase letter, convert the affected words to lower case and after sorting, it will use the map to replace the back the words in the sorted slice. This example is also useful if you are looking to replace element inside a slice/array that matches a mapping found in hash table.

Here you go!


 package main

 import (
 "fmt"
 "regexp"
 "sort"
 "strconv"
 "strings"
 "unicode"
 )

 func removeDelimString(str string) string {
 // alphanumeric (== [0-9A-Za-z])
 // \s is a white space character
 regExp := regexp.MustCompile(`[^[:alnum:]\s]`)
 return regExp.ReplaceAllString(str, "")
 }

 func sortWordsFixed(input string) string {

 var sorted sort.StringSlice
 originals := map[string]string{}
 var final []string

 unsorted := strings.Split(removeDelimString(input), " ")

 // test each word with first uppercase letter
 for k, v := range unsorted {
 if unicode.IsUpper(rune(v[0])) {
 // tag the words with first uppercase with their index number
 // this is to prevent wrong mapping later
 originals[strings.ToLower(v)+"["+strconv.Itoa(k)+"]"] = v
 sorted = append(sorted, strings.ToLower(v)+"["+strconv.Itoa(k)+"]")
 } else {
 sorted = append(sorted, v)
 }
 }

 // sort our words -- but all words start first letter in lowercase
 sort.Strings(sorted)

 // now, let's replaced back the original words with first uppercase character
 for _, v := range sorted {
 if strings.HasSuffix(v, "]") {
 final = append(final, originals[v])
 } else {
 final = append(final, v)
 }
 }

 return strings.Join(final, " ")
 }

 func sortWords(input string) string {
 var sorted sort.StringSlice

 // clean
 sorted = strings.Split(removeDelimString(input), " ") // convert to slice

 // bug?
 // words with initial uppercase letter will not be sorted!!
 sort.Strings(sorted)

 return strings.Join(sorted, " ")
 }

 func main() {
 text := `HEre is an Example of how to convert lines of text into a slice in golang, sort them in descending order and then display the sorted output`

 fmt.Println("Words sort with words with first uppercase letter. Notice that the words are not sorted:")
 fmt.Println("Before: ", text)
 fmt.Println("After: ", sortWords(text))

 fmt.Println("============================================")
 fmt.Println("With sortWordsFixed() function, the words with first uppercase letters are now sorted:")
 fmt.Println("Fixed: ", sortWordsFixed(text))
 }

Output:

Words sort with words with first uppercase letter. Notice that the words are not sorted:

Before: HEre is an Example of how to convert lines of text into a slice in golang, sort them in descending order and then display the sorted output

After: Example HEre a an and convert descending display golang how in in into is lines of of order output slice sort sorted text the them then to

============================================

With sortWordsFixed() function, the words with first uppercase letters are now sorted:

Fixed: a an and convert descending display Example golang HEre how in in into is lines of of order output slice sort sorted text the them then to

References:

https://www.socketloop.com/tutorials/golang-get-all-upper-case-or-lower-case-characters-from-string-example

https://golang.org/pkg/sort/#Strings

  See also : Golang : Get all upper case or lower case characters from string example





By Adam Ng

IF you gain some knowledge or the information here solved your programming problem. Please consider donating to the less fortunate or some charities that you like. Apart from donation, planting trees, volunteering or reducing your carbon footprint will be great too.


Advertisement