本文介绍在 Go 语言中,如何将包含星期缩写(如 "M"、"T"、"W" 等)的字符串切片,按照从周一到周日的自然顺序进行高效排序。核心思路是实现自定义 sort.Interface 接口,并借助映射表为每个缩写定义优先级。
在 Go 里处理具有明确语义顺序的数据(比如星期几)时,标准库的 sort 包并没有直接提供“按自定义顺序排序”的现成方案。你需要自己实现 sort.Interface 接口——也就是定义 Len()、Less() 和 Swap() 方法。说起来也不算复杂,但关键在于:星期缩写 "M"、"T"、"W" 等按字典序排列会完全混乱,不符合实际顺序。真正的顺序是周一、周二、周三……周日,必须严格对应。
最清晰、最高效的做法,是提前构建一个星期缩写到序号的映射表(map)。例如,将 "M" 对应 1,"T" 对应 2,一直到 "Su" 对应 7。然后在 Less 方法里,直接通过映射表的值来比较大小。这样一来,排序逻辑就变得像数字比较一样简单直观。
package main
import (
"fmt"
"sort"
)
type Days []string
// weekdayOrder 定义星期缩写到序号的映射(1=Monday, 7=Sunday)
var weekdayOrder = map[string]int{
"M": 1, // Monday
"T": 2, // Tuesday
"W": 3, // Wednesday
"Th": 4, // Thursday
"F": 5, // Friday
"S": 6, // Saturday
"Su": 7, // Sunday
}
func (d Days) Len() int { return len(d) }
func (d Days) Swap(i, j int) { d[i], d[j] = d[j], d[i] }
func (d Days) Less(i, j int) bool { return weekdayOrder[d[i]] < weekdayOrder[d[j]] }
func main() {
days := Days{"M", "Th", "W", "F", "T", "S", "Su"}
sort.Sort(days)
fmt.Println(days) // 输出:[M T W Th F S Su]
}
✅ 有几个关键点值得注意:
- 映射表
weekdayOrder最好定义为包级变量,而不是放在 Less 方法里每次比较都重新创建。否则每次比较都会重新分配 map,对性能影响较大——尤其是当切片规模较大时; - 所有缩写必须严格匹配映射表中的键(例如 "T" 只能表示 Tuesday,不能混用 "Tu" 或 "Tue")。如果实际数据来源不够规范,建议在排序前先进行一次输入校验或标准化预处理;
- 如果需要支持多种缩写格式(比如同时存在 "Tue" 和 "T"),可以在映射表中扩展多个键,或者统一转换为标准形式后再进行排序;
- 对于只有 7 个元素的小数据集,也有人用
strings.Index("MTWThFSu", d[i])这种方式来查找索引,但可读性较差,且无法处理多字符的缩写(如 "Th"、"Su" 等),不推荐使用。
总的来说,采用带语义映射的自定义 sort.Interface 是 Go 语言中处理这类有序枚举排序的推荐模式——效率高、可读性好、扩展方便。今后遇到类似问题(比如月份、星期、优先级等级),直接套用这个思路即可。
