Golang实现词频统计

本例使用golang实现词频统计。步骤:

(1)从文件中读取一篇文章。

(2)统计词频,按单词出现的频率从大到小进行排序。

(3)写入到文件中。

注:任何非英文字母的符号均认为是单词分隔符(即等同于空格)。

效率:使用本程序统计一篇150W单词的文章,大约需要70ms.

1.核心代码:

package wordtest

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"os"
	"runtime"
	"sort"
	"strings"
	"time"
)

//简单的词频统计任务
func CountTestBase(inputFilePath string, outputFilePath string) {
	//时间开始点
	start := time.Now().UnixNano() / 1e6

	//读取文件
	fileData, err := ioutil.ReadFile(inputFilePath)
	CheckError(err, "read file")
	var fileText string = string(fileData)

	//根据CPU核数新开协程
	newRountineCount := runtime.NumCPU()*2 - 1
	runtime.GOMAXPROCS(newRountineCount + 1)
	//切分文件
	parts := splitFileText(fileText, newRountineCount)

	var ch chan map[string]int = make(chan map[string]int, newRountineCount)
	for i := 0; i < newRountineCount; i++ {
		go countTest(parts[i], ch)
	}

	//主线程接收数据
	var totalWordsMap map[string]int = make(map[string]int, 0)
	completeCount := 0
	for {
		receiveData := <-ch
		for k, v := range receiveData {
			totalWordsMap[strings.ToLower(k)] += v
		}
		completeCount++

		if newRountineCount == completeCount {
			break
		}
	}

	//添加进slice,并排序
	list := make(WordCountBeanList, 0)
	for k, v := range totalWordsMap {
		list = append(list, NewWordCountBean(k, v))
	}
	sort.Sort(list)
	//时间结束点
	end := time.Now().UnixNano() / 1e6
	fmt.Printf("time consume:%dms\n", end-start)

	//输出
	wordsCount := list.totalCount()
	var data bytes.Buffer
	data.WriteString(fmt.Sprintf("程序执行:%dms\n", end-start))
	data.WriteString(fmt.Sprintf("文章总单词数:%d\n\n", wordsCount))
	for _, v := range list {
		var percent float64 = 100.0 * float64(v.count) / float64(wordsCount)
		_, err := data.WriteString(fmt.Sprintf("%s: %d, %3.2f%%\n", v.word, v.count, percent))
		CheckError(err, "bytes.Buffer, WriteString")
	}

	err = ioutil.WriteFile(outputFilePath, []byte(data.String()), os.ModePerm)
	CheckError(err, "ioutil.WriteFile")
}

func countTest(text string, ch chan map[string]int) {
	var wordMap map[string]int = make(map[string]int, 0)

	//按字母读取,除26个字母(大小写)之外的所有字符均认为是分隔符
	startIndex := 0
	letterStart := false
	for i, v := range text {
		if (v >= 65 && v <= 90) || (v >= 97 && v <= 122) {
			if !letterStart {
				letterStart = true
				startIndex = i
			}
		} else {
			if letterStart {
				wordMap[text[startIndex:i]]++
				letterStart = false
			}
		}
	}

	//最后一个单词
	if letterStart {
		wordMap[text[startIndex:]]++
	}
	ch <- wordMap
}

//将全文分成n段
func splitFileText(fileText string, n int) []string {
	length := len(fileText)
	parts := make([]string, n)

	lastPostion := 0
	for i := 0; i < n-1; i++ {
		position := length / n * (i + 1)
		for string(fileText[position]) != " " {
			position++
		}

		parts[i] = fileText[lastPostion:position]
		lastPostion = position
	}

	//最后一段
	parts[n-1] = fileText[lastPostion:]
	return parts
}

func CheckError(err error, msg string) {
	if err != nil {
		panic(msg + "," + err.Error())
	}
}

2.一个struct

package wordtest

type WordCountBean struct {
	word  string
	count int
}

func NewWordCountBean(word string, count int) *WordCountBean {
	return &WordCountBean{word, count}
}

type WordCountBeanList []*WordCountBean

func (list WordCountBeanList) Len() int {
	return len(list)
}

func (list WordCountBeanList) Less(i, j int) bool {
	if list[i].count > list[j].count {
		return true
	} else if list[i].count < list[j].count {
		return false
	} else {
		return list[i].word < list[j].word
	}
}

func (list WordCountBeanList) Swap(i, j int) {
	var temp *WordCountBean = list[i]
	list[i] = list[j]
	list[j] = temp
}

func (list WordCountBeanList) totalCount() int {
	totalCount := 0
	for _, v := range list {
		totalCount += v.count
	}

	return totalCount
}

3.主函数:

package main

import (
	"WordsTest/wordtest"
)

func main() {
	inputFilePath := "files/article.txt"
	outputFilePath := "files/hanjun-result.txt"

	wordtest.CountTestBase(inputFilePath, outputFilePath)
}
时间: 2024-08-29 05:25:12

Golang实现词频统计的相关文章

词频统计-单元测试

我自己的单元测试没有弄出来,我用c编的,在visual studio中貌似实现不了单元测试,而李俞寰同学是用c#编写的词频统计,在vs2015中实现单元测试无比的方便,所以我请教了他并借鉴了一下. [TestMethod()] public void DictionarySortTest() { Dictionary<string,int>input=new Dictionary<string,int>() { {"you,1}, {"are",1},

词频统计-功能一

一.完成一个小程序 我 拿到这个题目之后,就决定用最不熟悉的c#来实现,因为老师说不懂的去学才会有进步.布置任务后的第二天就开始去图书馆借了两本书<c#从入门到精髓>,<c#项目实战>,拿到书之后看了入门书<c#从入门到精髓>,看书的过程时痛苦的,因为发现大二选修课学的c#全交还给老师了,只能重头再学了.唯一有点印象的就是窗口应用程序,基于UI的设计. 写代码首先需要工具,由于电脑上没有visual studio的安装包,当时求助了度娘. 如果没有安装包的同学们,可以借

词频统计效能测试---------第二版

在第一次的词频统计中,对JProfile 款软件不是很熟悉,感觉数据不是很准确,在程序启动时JProfile总是提示Java虚拟机已退出,后来经过查阅知道解决方案:截图如下   要将 keep vm alive 勾选上. 程序总体总体情况如下: 当程序运行之后,cpu和内存的使用几乎在同一时间有一个明显的上升过程. 各个对象使用情况如下 下面是热点函数的展示,这也和我在程序中运用时间戳确定建树函数[generateCharTree()]占用时间较多的情况相符.因为对这个程序来说主要时间都花费在单

结对项目 - 词频统计Ⅱ

目的与要求 代码复审练习 结对练习 编写单元测试 基于上一个结对项目的结果,读取小文本文件A_Tale_of_Two_Cities.txt 或者 大文本文件Gone_with_the_wind.txt,统计某一指定单词在该文本文件中出现的频率. 命令行格式: 提示符> Myapp.exe -f filename.txt -w word (PS:C++ 程序,Java 程序输出方式类似) 解释: 选项 -f 表示打开某一文件 选项 -w 表示统计其后单词在打开的文件中的频率 详细内容 开发语言:J

个人项目——词频统计

前言: 开发工具:Visual Studio 2013 开发语言:C++ 源代码管理工具:Github Github源代码网址:https://github.com/superyy/YY1/blob/master/%E8%AF%8D%E9%A2%91%E7%BB%9F%E8%AE%A1main.cpp 预计各功能所花时间:some hours 实际各功能所花时间:some hours 性能提高所花时间:some hours 要求 :实现一个控制台程序,给定一段英文字符串,统计其中各个英文单词(4

实验二-3 Hadoop&amp;Paoding 中文词频统计

  参考教程 在Hadoop上使用庖丁解牛(较复杂,并未采用,可以之后试试) http://zhaolinjnu.blog.sohu.com/264905210.html Lucene3.3.Lucene3.4中文分词——庖丁解牛分词实例(屈:注意版本) http://www.360doc.com/content/13/0217/13/11619026_266124504.shtml 庖丁分词在hadoop上运行时的配置问题(采纳了一半,没有按照其所写配置dic属性文件) http://f.da

初学Hadoop之中文词频统计

1.安装eclipse 准备 eclipse-dsl-luna-SR2-linux-gtk-x86_64.tar.gz 安装 1.解压文件. 2.创建图标. ln -s /opt/eclipse/eclipse /usr/bin/eclipse #使符号链接目录 vim /usr/share/applications/eclipse.desktop #创建一个  Gnome 启动 添加如下代码: [Desktop Entry] Encoding=UTF-8 Name=Eclipse 4.4.2

第二周作业-词频统计

本周作业是词频统计,编程具体要求如下: https://edu.cnblogs.com/campus/nenu/SWE2017FALL/homework/922 对实现功能进行简要的介绍: 功能一:小文件输入,为表明程序能跑.需要在控制台下输入命令,得到文件中不重复的总单词数.并对单词出现的次数进行排序输出. 功能二:支持命令行输入英文作品的文件名,亲自录入,输出显示不重复单词总数,并对出现频率最高的前10的单词进行输出 功能三:支持命令行输入存储有英文作品文件的目录名,批量统计词频. 功能四:

软件工程第二次作业 词频统计

1.项目名称:词频统计 2.代码地址:https://coding.net/u/songyuu/p/python_wf/git 3.代码如下: 1 import os 2 import re 3 import collections 4 #print(os.getcwd()) #显示wf.py路径 5 #print(os.listdir())#显示目录下的文件 6 file_name=input("wf ") 7 if not os.path.isfile(file_name+'.tx