How to sort struct with multiple sort parameters?

Use the sort.Slice (available since Go 1.8) or the sort.Sort function to sort a slice of values.

With both functions, the application provides a function that tests if one slice element is less than another slice element. To sort by last name and then first name, compare last name and then first name:

if members[i].LastName < members[j].LastName {
    return true
}
if members[i].LastName > members[j].LastName {
    return false
}
return members[i].FirstName < members[j].FirstName

The less function is specified using an anonymous function with sort.Slice:

var members []Member
sort.Slice(members, func(i, j int) bool {
    if members[i].LastName < members[j].LastName {
        return true
    }
    if members[i].LastName > members[j].LastName {
        return false
    }
    return members[i].FirstName < members[j].FirstName
})

The less function is specified with through an interface with the sort.Sort function:

type byLastFirst []Member

func (members byLastFirst) Len() int           { return len(members) }
func (members byLastFirst) Swap(i, j int)      { members[i], members[j] = members[j], members[i] }
func (members byLastFirst) Less(i, j int) bool { 
    if members[i].LastName < members[j].LastName {
       return true
    }
    if members[i].LastName > members[j].LastName {
       return false
    }
    return members[i].FirstName < members[j].FirstName
}

sort.Sort(byLastFirst(members))

Unless performance analysis shows that sorting is a hot spot, use the function that's most convenient for your application.


Use the newer sort.Slice function as such:

sort.Slice(members, func(i, j int) bool {
    switch strings.Compare(members[i].FirstName, members[j].FirstName) {
    case -1:
        return true
    case 1:
        return false
    }
    return members[i].LastName > members[j].LastName
})

or something like that.