GitHub项目地址 |
结对伙伴作业地址 |
一、PSP表格
PSP | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 30 | 50 |
· Estimate | · 估计这个任务需要多少时间 | 1320 | 1470 |
Development | 开发 | 1200 | 1340 |
· Analysis | · 需求分析 (包括学习新技术) | 120 | 150 |
· Design Spec | · 生成设计文档 | 60 | 50 |
· Design Review | · 设计复审 (和同事审核设计文档) | 40 | 30 |
· Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 30 | 20 |
· Design | · 具体设计 | 50 | 85 |
· Coding | · 具体编码 | 720 | 870 |
· Code Review | · 代码复审 | 60 | 60 |
· Test | · 测试(自我测试,修改代码,提交修改) | 120 | 75 |
Reporting | 报告 | 120 | 130 |
· Test Report | · 测试报告 | 40 | 50 |
· Size Measurement | · 计算工作量 | 30 | 30 |
· Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 50 | 50 |
合计 | 1350 | 1520 |
结对时候的(非摆拍)照片
二、解题思路
刚开始拿到这个题的时候,我和队友稍微想了那么十秒钟左右,就很灵性地对彼此说“有点难搞”,的确,看到题目时确实没有太多的思路,但是大体方向还是有的。后面就进行了分工,我主要负责代码编写,我的结对伙伴负责在我遇到瓶颈的时候提供帮助,以及在我编写的过程中指出错误,以及后面我完成程序后他进行测试与性能分析。
在经过讨论后有了基本思路,然后决定设计一个Process接口,然后里面声明一些方法,具体的方法如下面的类图:
在后面的excute(后面才发现自己execute拼错了,但是问题不大)类中实现了这几个方法,最后在main里面调用方法实现需求。
在讨论出具体框架后,我自己先搭好了程序框架,但是还没有往里面填代码,然后git提交了第一次
三、代码规范与代码互审
代码规范详情见队友博客
代码互审环节在测试的时候,看到他的测试代码太简陋了,而且并没有使用到assert,直接通过肉眼观看,大幅度降低了自动化,一但数据量庞大起来就容易出错,所以给他指出了测试代码的问题。
四、代码说明
下面看一些关键的代码,首先是统计字符的部分,这部分实现比较简单,将文件读取后分别对每一行进行遍历,统计出总字符数
public int CountChar(string Fpath)
{
StreamReader sr = new StreamReader(Fpath);//在自定义path路径创建读文件流
string s;
char[] charArray;
int CountChar = 0;
while ((s = sr.ReadLine()) != null)
{
charArray = s.ToCharArray();//将读取的每一行送入char数组中
for (int j = 0; j < charArray.Length; j++)
{
CountChar++;//计算每一个字符
}
}
return CountChar;//返回有多少个字符
}
下面是统计行数的部分,这部分实现更加简单,相比于上面统计字符只需要一个循环就能搞定
public int CountLine(string Fpath)
{
//throw new NotImplementedException();
StreamReader sr = new StreamReader(Fpath);//创建读文件流
string s;
int line = 0;
while ((s = sr.ReadLine()) != null)//读取文件总行数
{
line++;
}
return line;//返回行数
}
下面是统计单词数,在这个地方遇到了一些困难,最开始想的是通过以前c语言啊很传统很笨的方式遍历,设置哨兵,然后统计,但是后面伙伴在搜集资料的时候给我讲了c#中dictionary的用法,我就在他的引导下使用字典完成了。
public int CountWord(string Fpath)
{
//throw new NotImplementedException();
excute doCount = new excute();
Dictionary<string, int> dictionary = CountFrequency(Fpath);
int CountWord = 0;
foreach (KeyValuePair<string, int> dic in dictionary)//遍历字典里面的每一个单词,结果为总单词数
{
CountWord += dic.Value;
}
return CountWord;
}
在统计单词频数的方法中也同样使用了字典
public Dictionary<string, int> CountFrequency(string Fpath)//计算每个单词的频数,结果传入字典并返回,字典中的key是单词的值,value是单词的频数
{
StreamReader sr = new StreamReader(Fpath);//创建读文件流
string s;
Dictionary<string, int> fre = new Dictionary<string, int>();
while ((s = sr.ReadLine()) != null)//读取文件的每一行到字符串s
{
string[] words = Regex.Split(s, " ");//将字符串s按空格分割
foreach (string word in words)//计算每行各个单词数
{
if (fre.ContainsKey(word))//判断字典是否包含该单词
{
fre[word]++;
}
else
{
fre[word] = 1;
}
}
}
return fre;
}
最后在main函数里面写附加功能
static void Main(string[] args)
{
StreamWriter sw = null;
Process count = new excute();
string path = null;//读入文件路径标志
string outPath = null;//写出文件路径标志
//string GetExNum = null;//限制输出个数的值
string GetNum = null;//指定频数的值
for (int i = 0; i < args.Length; i++)
{
switch (args[i])
{
case "-i":
path = args[i + 1];//寻找是否找到输入文件路径
break;
case "-n"://-n参数与数字搭配使用,用于限制最终输出的单词的个数
GetNum = args[i + 1];
break;
case "-o"://-o表示输出路径
outPath = args[i + 1];
break;
}
}
if (path != null)
{
if (outPath != null)
{
sw = new StreamWriter(outPath);//在outPath创建写文件流
}
Console.WriteLine("characters:" + count.CountChar(path));
Console.WriteLine("words:" + count.CountWord(path));
Console.WriteLine("lines:" + count.CountLine(path));
sw.WriteLine(String.Format("characters:" + count.CountChar(path)));
sw.WriteLine(String.Format("words:" + count.CountWord(path)));
sw.WriteLine(String.Format("lines:" + count.CountLine(path)));
if (GetNum != null)//将输出指定数量的单词数,并写入文件
{
int i = 0;
Dictionary<string, int> dictionary = count.CountFrequency(path);
dictionary = count.SortDictionary_Desc(dictionary);
foreach (KeyValuePair<string, int> dic in dictionary)
{
sw.WriteLine(String.Format("{0,-10} |{2,5}", dic.Key, 0, dic.Value));
Console.WriteLine(String.Format("{0,-10} |{2,5}", dic.Key, 0, dic.Value));
i++;
if (i == int.Parse(GetNum))
{
break;
}
}
}
}
else
{
Console.WriteLine("路径为空,请输入文件路径");
}
if (sw != null)
{
sw.Flush();
sw.Close();
}
最后程序整体完成后,也得到了预想的结果
在程序完成后,进行了git第二次提交(就不附截图了)
五、测试以及性能
六、收获与体会
说实话这次的作业一个人完成真的有点困难,虽说不是完成不了,但是在团队项目以及团队博客还有很多课的情况下时间肯定是不足够的,这也正体现了结对编程的作用,抽出一个下午的时间坐在一起敲代码,在自己遇到问题的时候有队友进行扶持,就算队友一时没有解决方案自己也可以继续下面的工作队友继续收集资料攻克困难然后回过来解决它,比单单一个人效率来的高,而且想的也会全面一点,真正有点体会到了1+1>2的这么个样子。