第11组结对编程 - 词频统计
一、GitHub地址
二、结对的PSP表格
PSP2.1 | Personal Software Process Stages | 预估耗时(h) | 实际耗时(h) |
Planning | 计划 | 7h | 8h |
·Estimate | · 估计这个任务需要多少时间 | 7h | 8h |
Development | 开发 | 4h | 5h |
·Analysis | · 需求分析 (包括学习新技术) | 0.3h | 0.3h |
·Design Spec | · 生成设计文档 | 0.5h | 0.5h |
·Design Review | · 设计复审 (和同事审核设计文档) | 0.4h | 0.4h |
·Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 0.3h | 0.3h |
·Design | · 具体设计 | 0.3 | 0.3h |
·Coding | · 具体编码 | 1.5h | 2.5h |
·Code Review | · 代码复审 | 0.4h | 0.4h |
·Test | · 测试(自我测试,修改代码,提交修改) | 0.3h | 0.3h |
Reporting | 报告 | 3h | 3h |
· Test Report | · 测试报告 | 0.5h | 0.6h |
· Size Measurement | · 计算工作量 | 0.5h | 0.4h |
· Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 2h | 2h |
合计 | 7h | 8h |
三、解题思路描述。即刚开始拿到题目后,如何思考,如何找资料的过程
1.读文件用什么好?用scanner读取文件
2.正则表达式如何写?求助正则表达式的百度百科
3.字符如何计数?若Ascii码在0-127之间则计数
4.单词如何计数?使用map的containsKey
5.如何对单词个数进行排序?使用list存map,并对map的value值进行排序( Collections.sort(list,valueComparator))
四、设计实现过程。设计包括代码如何组织,比如会有几个类,几个函数,他们之间关系如何,关键函数是否需要画出流程图?单元测试是怎么设计的?
一个主函数,调用两个函数,countChar(File file,PrintStream printStream)函数统计字符数,countWord(File file, PrintStream printStream)统计单词数,并对单词的频率进行排序,两个函数之间没有关联。
单元测试设计
import org.junit.Assert;
import java.io.File;
import java.io.PrintStream;
import static org.junit.Assert.*;
public class wordCountTest {
@org.junit.Test
public void countWord()throws Exception {
//wordCount wordCount = new wordCount();
File file = new File("txt/input.txt");
File file1 = new File("Out.txt");
PrintStream printStream = new PrintStream(file1);
Integer sum= wordCount.countChar(file,printStream);
Assert.assertEquals("5", sum.toString());
}
}
五、记录在改进程序性能上所花费的时间,描述你改进的思路,并展示一张性能分析图(由VS 2017的性能分析工具自动生成),并展示你程序中消耗最大的函数。
1.正则表达式花费时间较长,原来是只分割空格,后面加入正则表达式,分割空格,非字母数字空格,改进后的正则表达式为“\s*[0-9a-zA-Z]+”,'\'是\的转义符,'\s'是空格,'*'是零个或多个,'[0-9a-zA-Z]'为非字母数字字符,‘+’表示一次或多次,大概花费35min
2.在单词计数并排序的时候,使用list存map,并对map的value进行排序,大概花费30min
性能分析图
改进之后的效能分析图
六、代码说明
1,使用scanner扫描文件
2,统计Ascii码,扫描每个字符,若在Ascii码区间则计数
3,统计单词总数,两个正则表达式
String argex = "\\s*[^0-9a-zA-Z]+";
String argex1="[a-zA-Z]{4,}[a-zA-Z0-9]*";
argex 分隔符,筛选出每行的字母数字;argex1匹配是否至少以4个英文字母开头的单词
4,统计有效行数
if (!charline.trim().isEmpty()){
line++;
}
5.统计文件中各单词的出现次数,最终只输出频率最高的10个。频率相同的单词,优先输出字典序靠前的单词
if (id_word){
String key = a[i].toLowerCase();
if (map.containsKey(key)){
n=Integer.parseInt(map.get(key).toString())+1;
map.put(key,n);
}else {
map.put(key,1);
}
}
使用Map,key存单词,value存单词对应的个数,然后对单词个数进行排序
// map转换成list进行排序
List<Map.Entry<String, Integer>> list = new ArrayList<Map.Entry<String,Integer>>(map.entrySet());
// 排序
Collections.sort(list,valueComparator);
// 升序比较器
Comparator<Map.Entry<String, Integer>> valueComparator = new Comparator<Map.Entry<String,Integer>>() {
@Override
public int compare(Map.Entry<String, Integer> o1,
Map.Entry<String, Integer> o2) {
// TODO Auto-generated method stub
if (o2.getValue()==o1.getValue()){
int ab = o2.getKey().compareTo(o1.getKey());
return ab;
}else {
return o2.getValue()-o1.getValue();
}
}
};
for (Map.Entry<String, Integer> entry : list) {
if (is_out!=entry.getValue()){
printStream.println("<"+entry.getKey()+">:" + entry.getValue());
is_out=entry.getValue();
count1++;
if (count1==10){
break;
}
}
}
使用list将每个map存起来,并对map的value值进行排序,并输出频率最高的十个,单词频率相同时,compareTo可以比较出字典序靠前的单词
测试结果图
七、异常模块处理
public static void countChar(File file,PrintStream printStream)throws FileNotFoundException
异常捕获主要是在使用Scanner和PrintStream时需要捕获异常或者抛异常。
八、收获与心得
这次与亓老师一起结对,感觉自己学习了很多,在亓老师的指导下少走了很多弯路,大大提高了代码效率,也由此明白了团队协作的重要性。