我最近在尝试对包含法语字符串的键的结构进行排序时遇到了一个问题。根据法语字母排序规则,经典的sort.SliceStable
没有正确考虑重音字符
值得庆幸的是,collate包做得很好,但如果不将其与sort.SliceStable
函数结合使用,我就找不到在结构上直接使用该包的方法。
这是我想出的,似乎是正确的工作:
import (
"fmt"
"sort"
"golang.org/x/text/collate"
"golang.org/x/text/language"
)
type SortFr struct {
Order int
Fr string
}
func main() {
// the int SortFr.Order reflects the correct french sort order
s := []SortFr{
SortFr{2, "côte"},
SortFr{0, "cote"},
SortFr{5, "coter"},
SortFr{1, "coté"},
SortFr{4, "cotée"},
SortFr{3, "côté"},
}
// incorrect sort order
sort.SliceStable(s, func(i, j int) bool {
return s[i].Fr < s[j].Fr
})
fmt.Println(s)
// correct sort order
cl := collate.New(language.French)
sort.SliceStable(s, func(i, j int) bool {
return cl.CompareString(s[i].Fr, s[j].Fr) == -1
})
fmt.Println(s)
}
此代码返回:
[{0 cote} {5 coter} {1 coté} {4 cotée} {2 côte} {3 côté}]
[{0 cote} {1 coté} {2 côte} {3 côté} {4 cotée} {5 coter}]
这是在大型结构上最有效的方法吗?
您的排序基于一个简单调用cl.CompareString()
的less函数。你希望什么更简单?您必须以某种方式/在什么地方根据Fr
字段进行排序,这就是您可以做到的。
sort.SliceStable()
在某种程度上是通用的,它可以对任何切片进行排序。为此,它必须在引擎盖下使用反射,这比不必使用反射的解决方案要慢。因此,如果你想对一大块进行排序,那么实现sort.Interface
是有利可图的。
var cl = collate.New(language.French)
type FrSlice []SortFr
func (s FrSlice) Len() int { return len(s) }
func (s FrSlice) Less(i, j int) bool { return cl.CompareString(s[i].Fr, s[j].Fr) < 0 }
func (s FrSlice) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
然后使用它:
s := []SortFr{
// ...
}
sort.Stable(FrSlice(s))
还要注意,sort.Sort()
可能比sort.Stable()
快一些,因为前者不必保证相等元素的原始顺序。因此,如果不要求保持元素的原始顺序相等,则使用sort.Sort()
。