Go 语言大白话入门 10 - 排序与常用数据操作

排序与常用数据操作

本章目标

本章目标是把你手里的数据真正用起来:会排序、会查找、会去重、会反转。 看完后你至少能独立处理一组切片数据,不再只会"存进去"。

常见坑位

先看最常见的翻车点:

  1. 以为排序会返回新切片,结果原数据被改了。
  2. 自定义排序比较逻辑写反,升序写成降序。
  3. BinarySearch 直接用在无序切片上,查找结果不可信。
  4. 去重时想保留原顺序,却用了"先排序再去重"的方案。
  5. Contains 当高性能查找用在超大数据上,性能不稳定。

先建立主线:这章到底在解决什么

上一章你学了切片和 map,已经能把数据放进容器。 但业务里更常见的问题是:

  1. 我要把列表按规则排好。
  2. 我要判断某个值在不在。
  3. 我要把重复数据清掉。
  4. 我要临时倒序输出。

这章就围绕这 4 个动作展开。

基础排序:slices.Sort

Go 1.21+ 推荐用标准库 slices 包做基础排序。 先跑最小可运行示例:

go 复制代码
package main

import (
    "fmt"
    "slices"
)

func main() {
    nums := []int{5, 2, 8, 1, 9, 3}
    slices.Sort(nums) // 原地升序排序

    fmt.Println(nums) // [1 2 3 5 8 9]
}

关键点:slices.Sort 是原地修改,不返回新切片。

自定义排序:slices.SortFunc

当你要按结构体字段排序时,用 slices.SortFunc。 这里先把结构体当成"把多个字段绑在一起的数据块",下一章再细讲结构体。

go 复制代码
package main

import (
    "cmp"
    "fmt"
    "slices"
)

type Student struct {
    Name  string
    Score int
}

func main() {
    students := []Student{
        {Name: "小明", Score: 88},
        {Name: "小红", Score: 95},
        {Name: "小刚", Score: 72},
    }

    // 按分数降序
    slices.SortFunc(students, func(a Student, b Student) int {
        return cmp.Compare(b.Score, a.Score)
    })

    for _, student := range students {
        fmt.Printf("%s: %d\n", student.Name, student.Score)
    }
}

判断升降序的简单口诀:

  1. 升序:cmp.Compare(a, b)
  2. 降序:cmp.Compare(b, a)

判断是否有序:slices.IsSorted

如果你不确定一组数据是不是已经排好,可以先判断:

go 复制代码
package main

import (
    "fmt"
    "slices"
)

func main() {
    nums := []int{1, 2, 3, 5, 8}
    fmt.Println(slices.IsSorted(nums)) // true
}

这个函数不常用,但在"避免重复排序"时很实用。

查找元素:Contains 和 BinarySearch

无序切片:slices.Contains

go 复制代码
package main

import (
    "fmt"
    "slices"
)

func main() {
    fruits := []string{"苹果", "香蕉", "橘子"}
    fmt.Println(slices.Contains(fruits, "香蕉")) // true
    fmt.Println(slices.Contains(fruits, "西瓜")) // false
}

Contains 是线性遍历,数据量小到中等完全够用。

有序切片:slices.BinarySearch

如果数据已经排好序,查找建议用二分:

go 复制代码
package main

import (
    "fmt"
    "slices"
)

func main() {
    fruits := []string{"苹果", "橘子", "香蕉"}
    slices.Sort(fruits) // BinarySearch 前必须先排序

    index, found := slices.BinarySearch(fruits, "香蕉")
    fmt.Printf("found=%v, index=%d\n", found, index)
}

注意:找不到时返回的 index 是"可插入位置",不是 -1

去重:保序和不保序两种思路

保留原始顺序:map 标记法

go 复制代码
package main

import "fmt"

func uniqueKeepOrder(items []string) []string {
    seen := make(map[string]bool)
    result := make([]string, 0, len(items))

    for _, item := range items {
        if seen[item] {
            continue
        }
        seen[item] = true
        result = append(result, item)
    }

    return result
}

func main() {
    tags := []string{"go", "web", "go", "api", "web"}
    fmt.Println(uniqueKeepOrder(tags)) // [go web api]
}

不要求原顺序:排序 + Compact

go 复制代码
package main

import (
    "fmt"
    "slices"
)

func main() {
    tags := []string{"go", "web", "go", "api", "web"}

    slices.Sort(tags)
    tags = slices.Compact(tags)

    fmt.Println(tags) // [api go web]
}

这一招只会去掉"相邻重复项",所以必须先排序。

反转切片:slices.Reverse

go 复制代码
package main

import (
    "fmt"
    "slices"
)

func main() {
    words := []string{"a", "b", "c", "d"}
    slices.Reverse(words) // 原地反转

    fmt.Println(words) // [d c b a]
}

动手练习

  1. 准备一个整数切片,先 Sort,再 Reverse,观察结果。
  2. 写一个结构体切片,用 SortFunc 按分数字段升序和降序各排一次。
  3. Contains 判断一个标签在不在。
  4. BinarySearch 在有序切片中查找元素,并打印 foundindex
  5. 分别用"map 保序去重"和"Sort+Compact 去重"对同一组数据处理,对比结果。

过关标准

满足下面 6 条,这章就算过关:

  1. 你知道 slices.Sort 会原地修改数据。
  2. 你能写出 SortFunc 的升序和降序比较逻辑。
  3. 你知道 BinarySearch 必须在有序切片上使用。
  4. 你能区分保序去重和排序去重的差异。
  5. 你会用 ContainsIsSortedReverse 三个常用函数。
  6. 你能自己写出一个完整的小示例并跑通。

下一章衔接

下一章我们讲结构体 struct,把多个关联字段组织成真正可维护的数据模型。

本文章属于《Go语言大白话入门》零基础全套教程,持续更新、全程实操练手。 微信公众号【码栈研说】超前更新,目前比掘金领先 30 章内容,完整连载、无删减、持续日更,需要完整系统学习的读者可自行前往查看。

文中部分内容借助 AI 辅助梳理,全文人工校验、实操落地。

相关推荐
JavaGuide2 小时前
再见 Superpowers!很多 Skill 真的可以扔掉了。
后端·ai编程
小阿鑫3 小时前
一个 AI 应用开发程序员的一天,都在屏幕前忙些什么?
ai·程序员·agent·rd270q·明基rd270q
用户7713970207064 小时前
我在项目里发现了一个“神秘文件“——.editorconfig
后端
盏灯4 小时前
mac 外接磁盘,热更新失效
前端·后端
ihuyigui4 小时前
海外签收通知短信接口
android·java·开发语言·前端·数据库·后端
腾渊信息科技公司4 小时前
Spring Boot + TDengine:工业视觉检测数据实时同步方案实战
spring boot·后端·tdengine
用户40966601317514 小时前
MyBatis、MyBatis-Plus、通用 Mapper:一张图说清三者的血缘关系
后端
爬楼的猪5 小时前
WSL 的 GUI 为什么总是卡卡的
后端
猿的天空5 小时前
机器人双手迎来全栈训练系统:灵初智能EgoSteer让灵巧手无所不能
网络·人工智能·计算机·ai·程序员·机器人·编程