50周学习go语言:第五周 复合类型与词频统计

ops/2025/2/28 12:16:58/

以下是第五周复合类型(数组、切片与映射)的详细学习内容,按照第四周的深度要求设计:


第五周:复合类型与词频统计


一、复合类型详解

1. 数组(Array)
// 声明与初始化
var arr1 [3]int           // 声明:[0 0 0]
arr2 := [3]string{"A", "B", "C"}  // 显式初始化
arr3 := [...]int{1,2,3}   // 编译器推断长度// 特性:
// - 固定长度(长度是类型的一部分)
// - 值传递(赋值/传参产生副本)
// - 内存连续分配// 操作示例:
arr := [5]int{10,20,30,40,50}
fmt.Println(arr[1])       // 20
arr[2] = 35               // 修改元素
fmt.Println(len(arr))     // 5(长度)
fmt.Println(cap(arr))     // 5(容量)
2. 切片(Slice)
// 创建方式
s1 := make([]int, 3, 5)   // 类型,长度,容量
s2 := []float64{1.1, 2.2} // 字面量
s3 := arr[1:3]            // 从数组切割// 特性:
// - 动态大小(自动扩容)
// - 引用类型(底层数组视图)
// - 包含ptr/len/cap三元组// 操作示例:
s := []int{10,20,30}
s = append(s, 40)         // 扩容追加
copy(s[1:], s[2:])        // 删除元素(20)
s = s[:len(s)-1]          // 新长度:[10 30 40]
3. 映射(Map)
// 初始化方式
m1 := make(map[string]int)
m2 := map[string]float64{"pi": 3.1415,"e":  2.7182,
}// 特性:
// - 无序键值对集合
// - 引用类型
// - 线程不安全// 操作示例:
ages := map[string]int{"Alice": 25,"Bob":   30,
}
ages["Charlie"] = 28      // 添加/修改
delete(ages, "Bob")       // 删除
if age, ok := ages["David"]; !ok {fmt.Println("不存在")
}

二、词频统计任务

需求分析
  1. 输入一段英文文本
  2. 输出单词出现频率(不区分大小写)
  3. 过滤标点符号和数字
  4. 支持并发处理(可选优化)
版本1:基础实现
func wordFrequency(text string) map[string]int {// 清理文本cleaner := func(r rune) rune {if unicode.IsLetter(r) {return unicode.ToLower(r)}return ' ' // 非字母转为空格}cleaned := strings.Map(cleaner, text)// 分割单词words := strings.Fields(cleaned)// 统计频率freq := make(map[string]int)for _, word := range words {freq[word]++}return freq
}
版本2:并发优化
func concurrentWordFrequency(text string) map[string]int {// 文本预处理(同上)cleaner := func(r rune) rune {/* 同版本1 */}cleaned := strings.Map(cleaner, text)words := strings.Fields(cleaned)// 并发处理var mu sync.Mutexvar wg sync.WaitGroupfreq := make(map[string]int)chunkSize := 1000for i := 0; i < len(words); i += chunkSize {end := i + chunkSizeif end > len(words) {end = len(words)}chunk := words[i:end]wg.Add(1)go func(words []string) {defer wg.Done()localFreq := make(map[string]int)for _, w := range words {localFreq[w]++}mu.Lock()for k, v := range localFreq {freq[k] += v}mu.Unlock()}(chunk)}wg.Wait()return freq
}

三、测试与性能

1. 表格驱动测试
func TestWordFrequency(t *testing.T) {tests := []struct {input stringwant  map[string]int}{{"Hello hello world",map[string]int{"hello":2, "world":1},},{"Go! 100% Go...",map[string]int{"go":2},},{"A man a plan a canal: Panama",map[string]int{"a":3, "man":1, "plan":1, "canal":1, "panama":1},},}for _, tt := range tests {got := wordFrequency(tt.input)if !reflect.DeepEqual(got, tt.want) {t.Errorf("输入 %q\n期望 %v\n实际 %v", tt.input, tt.want, got)}}
}
2. 性能基准测试
# 运行测试
go test -bench . -benchmem# 预期结果:
BenchmarkWordFrequency-8             5000    324521 ns/op   138920 B/op    502 allocs/op
BenchmarkConcurrent-8                8000    198745 ns/op   189654 B/op   1502 allocs/op

四、进阶技巧

1. 内存优化(预分配)
// 预估容量减少扩容
words := make([]string, 0, len(text)/5)  // 按平均单词长度5预估
freq := make(map[string]int, 1000)       // 预分配哈希表槽位
2. 正则表达式优化
// 使用正则分割更高效
re := regexp.MustCompile(`\W+`)
words := re.Split(strings.ToLower(text), -1)
3. 自定义排序输出
func sortedFrequency(freq map[string]int) []string {type pair struct {word  stringcount int}pairs := make([]pair, 0, len(freq))for k, v := range freq {pairs = append(pairs, pair{k, v})}sort.Slice(pairs, func(i, j int) bool {return pairs[i].count > pairs[j].count})result := make([]string, len(pairs))for i, p := range pairs {result[i] = fmt.Sprintf("%s:%d", p.word, p.count)}return result
}

五、扩展练习

  1. 停用词过滤

    func filterStopWords(freq map[string]int, stopWords map[string]struct{}) {for w := range freq {if _, exists := stopWords[w]; exists {delete(freq, w)}}
    }
    
  2. 词云生成器

    func generateWordCloud(freq map[string]int, size int) []string {// 根据频率生成不同字号标记// 示例:["GO(12)", "语言(8)", "并发(20)"]
    }
    

六、学习检查清单

  • 能正确定义数组、切片和映射
  • 理解切片扩容机制(容量翻倍策略)
  • 会使用sync.Mutex处理并发map访问
  • 能解释数组与切片的底层关系
  • 理解map的哈希表实现原理
  • 会进行切片的内存预分配优化
  • 能处理Unicode字符的文本清洗
  • 会编写并发安全的统计程序

通过本学习内容,您将掌握Go语言核心复合类型的特性和高效使用方法,并能够根据实际场景选择最佳数据结构。建议:

  1. 尝试处理1GB以上的大文本文件
  2. 比较不同分块策略对并发版本的影响
  3. 使用pprof分析内存分配热点
  4. 实现扩展练习中的词云可视化功能

http://www.ppmy.cn/ops/161955.html

相关文章

GoLand 安装包 绿色版 Win,Mac,Linux 包含IntelliJ全家桶 专为Go语言设计的集成开发环境(IDE)

下载链接&#xff1a; https://pan.baidu.com/s/1cfkJf6Zgxc1XfYrVpwtHkA?pwd1234 导语&#xff1a;JetBrains旗下GoLand以智能代码补全率98%、深度Go模块支持和跨平台调试工具&#xff0c;成为2025年Gopher首选IDE。本文涵盖环境配置、效率革命、框架集成、性能调优、团队协…

视频HDR技术详解,你的电脑怎么播放HDR视频?

闲聊&#xff1a;前两天在b站上面看到影视飓风的视频&#xff0c;让我有点疑惑&#xff0c;我不知道为什么播放视频有设备撑不住一说&#xff0c;所以感兴趣去ytb下载了4k原片30hz刷新的&#xff0c;然后测试一下我的电脑能不能播放&#xff0c;发现还是可以的&#xff0c;视觉…

每日学习Java之一万个为什么?[MySQL面试篇]

分析SQL语句执行流程中遇到的问题 前言1 MySQL是怎么在一台服务器上启动的2 MySQL主库和从库是同时启动保持Alive的吗&#xff1f;3 如果不是主从怎么在启动的时候保证数据一致性4 ACID原则在MySQL上的体现5 数据在MySQL是通过什么DTO实现的6 客户端怎么与MySQL Server建立连接…

【论文阅读笔记】FcaNet: Frequency Channel Attention Networks(2021/7/23)

目录 1 引言 2 方法 1 DCT和通道注意力 2 多光谱通道注意力(Multi-Spectral Channel Attention) 3 频率成分的选择标准 3 实验 4 结论 论文题目&#xff1a;FcaNet: Frequency Channel Attention Networks(频率通道注意力网络) 论文地址&#xff1a;https://arxiv.org/p…

cpp每日温度(单调栈)

题目如下 输入n和n个温度值&#xff0c;输出所找到对应温度后面比其更大的温度值 代码及解析如下&#xff1a; 谢谢观看&#xff01;&#xff01;&#xff01;

Java集合并发安全面试题

Java集合并发安全面试题 同步包装器 Q1: Collections的同步包装器是如何实现线程安全的&#xff1f; public class SynchronizedWrapperExample {// 1. 基本使用public void demonstrateSynchronizedCollections() {// 创建同步ListList<String> syncList Collection…

STM32-智能台灯项目

一、项目需求 1. 红外传感器检测是否有人&#xff0c;有人的话实时检测距离&#xff0c;过近则报警&#xff1b;同时计时&#xff0c;超过固定时间则报警&#xff1b; 2. 按键 1 切换工作模式&#xff1a;智能模式、按键模式、远程模式&#xff1b; 3. 智能模式下&#xff0c;根…

C高级(shell)

作业 1、使用case...in实现等级判断 2、计算各个位数和 3、计算家目录下目录个数和普通文件数 4、打印图形 5、冒泡排序