Go语言中如何排序切片的切片?如何实现切片间的比较并泛型化sort.Interface?
嘿,这个问题我之前做类似需求的时候刚好研究过!
你说的没错,Go语言里字符串能直接用>、<做字典序比较,但切片不行——因为切片是引用类型,语言原生只支持判断是否为nil或者用==比较两个切片是否指向同一个底层数组且长度相同(元素也得全部相等),没法直接做大小比较。
要实现像字符串那样的切片比较,进而对[][]int排序,还支持泛型的话,我们可以这么搞:
第一步:写一个泛型的切片比较函数
先封装一个通用的sliceLess函数,用来按字典序比较两个同类型的切片,逻辑和字符串比较一致:先逐个比较对应位置的元素,遇到第一个不同的元素就返回结果;如果前面元素都相同,短的切片更小。
func sliceLess[T comparable](a, b []T) bool { minLen := min(len(a), len(b)) for i := 0; i < minLen; i++ { if a[i] != b[i] { return a[i] < b[i] } } // 前minLen个元素都相等,长度更短的切片更小 return len(a) < len(b) }
这里用了Go 1.18+的泛型特性,T comparable约束确保元素类型支持==和<比较。
第二步:实现泛版的sort.Interface
如果你需要严格实现sort.Interface接口(比如要复用这个排序逻辑),可以定义一个泛型类型,然后给它实现接口的三个方法:
// 定义泛型的切片的切片类型 type SliceOfSlices[T comparable] [][]T // Len 返回外层切片的长度 func (s SliceOfSlices[T]) Len() int { return len(s) } // Swap 交换两个元素的位置 func (s SliceOfSlices[T]) Swap(i, j int) { s[i], s[j] = s[j], s[i] } // Less 调用我们的泛型比较函数判断顺序 func (s SliceOfSlices[T]) Less(i, j int) bool { return sliceLess(s[i], s[j]) }
第三步:实际使用示例
现在就可以用这个泛型类型来排序[][]int了,比如:
package main import ( "fmt" "sort" ) // 这里放上面的sliceLess函数和SliceOfSlices类型及方法 func main() { // 测试数据 nums := [][]int{{1,2}, {2,1}, {1,1}, {2}, {1,2,3}} // 转换成泛型类型 sortedNums := SliceOfSlices[int](nums) sort.Sort(sortedNums) fmt.Println(sortedNums) // 输出:[[1 1] [1 2] [1 2 3] [2] [2 1]] }
更简洁的替代方案:用sort.Slice
如果不需要复用sort.Interface的实现,直接用sort.Slice函数更省事,把泛型比较函数传进去就行:
sort.Slice(nums, func(i, j int) bool { return sliceLess(nums[i], nums[j]) })
这样不用定义新类型,代码更紧凑。
这个泛型实现不仅支持[][]int,只要元素类型是comparable(比如string、float64、自定义的可比较类型),[][]string、[][]float64之类的都能直接用,非常灵活。
内容的提问来源于stack exchange,提问作者eNV25
相关产品推荐
相关产品推荐

