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

news/2025/2/26 5:56:15

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


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


一、复合类型详解

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.Mutex
    var wg sync.WaitGroup
    freq := make(map[string]int)
    
    chunkSize := 1000
    for i := 0; i < len(words); i += chunkSize {
        end := i + chunkSize
        if 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 string
        want  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  string
        count 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.niftyadmin.cn/n/5868118.html

相关文章

angular贪吃蛇

说明&#xff1a;我计划用angular实现一个贪吃蛇的程序&#xff0c;并且有方向键去控制蛇的上下左右的移动&#xff0c;并且有得分系统&#xff0c;当蛇撞到墙壁或者自身&#xff0c;游戏结束 效果图&#xff1a; step1: C:\Users\Administrator\WebstormProjects\untitled4\…

前缀和代码解析

前缀和是指数组一定范围的数的总和,常见的有两种,一维和二维,我会用两道题来分别解析 一维 DP34 【模板】前缀和 题目: 题目解析: 暴力解法 直接遍历数组,遍历到下标为 l 时,开始进行相加,直到遍历到下标为 r ,最后返回总和.这样做的时间复杂度为: O(n) public class Main …

[字节青训_AI对话框]SSE交互规范、自定义事件、前后端数据传递、状态监听、连接和断开详解

1.SSE基础 以下是关于 Server-Sent Events (SSE) 的前后端交互规范、常见方法及自定义扩展的完整指南: 一、SSE 交互规范 1. 基础协议 HTTP 协议:基于 HTTP/1.1 长连接,响应头需包含:Content-Type: text/event-streamCache-Control: no-cacheConnection: keep-alive2. 数…

deepseek部署:ELK + Filebeat + Zookeeper + Kafka

## 1. 概述 本文档旨在指导如何在7台机器上部署ELK&#xff08;Elasticsearch, Logstash, Kibana&#xff09;堆栈、Filebeat、Zookeeper和Kafka。该部署方案适用于日志收集、处理和可视化场景。 ## 2. 环境准备 ### 2.1 机器分配 | 机器编号 | 主机名 | IP地址 | 部署组件 |-…

WIFI的SSID超长,隐藏,重复 (2.4G和5G差异)

目录 1、2.4G和5G的频率范围‌ 2、2.4G和5G的差异‌&#xff1a; 3、隐藏ssid显示为\x00 4、 重复的ssid名称 扩展 前言 最近处理wifi设备时发现&#xff0c;小小一个ssid就有超多的问题。 不是中文转义就是超长&#xff0c;现在还发现空字符的&#xff0c;原来时对方路由隐藏了…

【实战 ES】实战 Elasticsearch:快速上手与深度实践-1.1.1对比传统数据库与搜索引擎(MySQL vs ES)

&#x1f449; 点击关注不迷路 &#x1f449; 点击关注不迷路 &#x1f449; 点击关注不迷路 文章大纲 为什么选择Elasticsearch&#xff1f;——从MySQL到Elasticsearch的深度对比引言一、核心概念对比1. 数据模型差异2. 查询语言对比 二、适用场景对比1. MySQL的典型场景2. E…

CPU多级缓存机制

目录 一、前置知识 ---- CPU的核心 1.1. 单核与多核CPU 二、CPU多级缓存机制 三. 缓存的基本结构/缓存的存储结构 四、CPU缓存的运作流程/工作原理 五、CPU多级缓存机制的工作原理【简化版】 5.1. 缓存访问的过程 (5.1.1) L1缓存&#xff08;一级缓存&#xff09;访问 …

Nginx的安装和部署以及Nginx的反向代理与负载均衡

Nginx的安装和部署以及Nginx的反向代理与负载均衡 1. 本文内容 Nginx的安装Nginx的静态网站部署Nginx的反向代理与负载均衡&#xff0c;配置反向代理与负载均衡 2. Nginx的安装与启动 2.1 什么是Nginx Nginx是一款高性能的http服务器/反向代理服务器及电子邮件&#xff08…