1、做業地址git
Github項目地址:https://github.com/gentlemanzq/WordCount.git(用的是同伴的)
github
做業連接:https://edu.cnblogs.com/campus/xnsy/SoftwareEngineeringClass1/homework/2882算法
結對同伴博客地址:https://www.cnblogs.com/gentlemanzq/編程
個人博客地址:https://www.cnblogs.com/Ysml/框架
2、結對過程描述函數
2.1 整體狀況分析性能
首先,根據題目要求,將代碼分解爲幾個模塊,確立好每一個模塊的具體函數內容。其次,根據我的的編程能力,將不一樣模塊分配給單元測試
相應的人 進行完成。分配任務後,兩人一塊兒完成,其中一人完成本身相應模塊的編程,另一個便審查代碼,指出錯誤之處或者不一樣學習
的思路與看法,最後兩人相互討論,選取最優的編程方法。測試
2.2 存在的問題
因爲兩人的編程水平存在差別,有時存在沒法理解同伴編寫代碼的具體意思,又由於思路的不一樣,存在代碼具體位置的爭論。
2.3 解決方法
對存在的問題,單獨拉出來,由編程的人對不理解的人進行講解,其次對相應調用函數的不認,經過百度進行了解認識。
附結對照片:
3、PSP表格
PSP2.1 | Personal Software Process Stages | 預估耗時(分鐘) | 實際耗時(分鐘) |
Planning | 計劃 | 30 | 45 |
· Estimate | · 估計這個任務須要多少時間 | 60 | 60 |
Development | 開發 | 45 | 60 |
· Analysis | · 需求分析 (包括學習新技術) | 10 | 15 |
· Design Spec | · 生成設計文檔 | 5 | 8 |
· Design Review | · 設計複審 (和同事審覈設計文檔) | 10 | 10 |
· Coding Standard | · 代碼規範 (爲目前的開發制定合適的規範) | 5 | 5 |
· Design | · 具體設計 | 20 | 30 |
Coding | · 具體編碼 | 90 | 120 |
· Code Review | · 代碼複審 | 45 | 60 |
· Test | · 測試(自我測試,修改代碼,提交修改) | 60 | 80 |
Reporting | 報告 | 100 | 120 |
· Test Report | · 測試報告 | 45 | 50 |
· Size Measurement | · 計算工做量 | 20 | 20 |
· Postmortem & Process Improvement Plan | · 過後總結, 並提出過程改進計劃 | 15 | 10 |
合計 | 560 | 693 |
4、解題思路
拿到題目後,先仔細閱讀題目,咱們根據題目要求,構建了一個大概的框架,將題目要求分解成不一樣的模塊。而後根據模塊的內容
找出學過相對應的代碼內容。隨後思考代碼的可行性,是否存在漏洞。遇到不會編寫的代碼,上網查找資料,圖書館借閱書籍查找相關問題。
5、設計實現過程
經過審讀題目要求,能夠將整個程序分爲以下部分:
1.統計文件字符數函數
2.統計有效行數函數
3.統計文件中各單詞的出現次數函數,並只輸出頻率最高的10個。頻率相同的單詞,優先輸出字典序靠前的單詞。
4.將程序輸出結果寫入txt文件函數 (幾個函數相互獨立)
(當對代碼進行封裝時,就能夠將以上每一個函數封裝成類,須要用時,能夠直接調用。)
統計文件中各單詞的出現次數函數,並只輸出頻率最高的10個。頻率相同的單詞,優先輸出字典序靠前的單詞。爲關鍵函數,流程圖以下:
(算法關鍵、獨特之處:提取單詞的時候,一併統計了頻率。而且在輸出排序時,調用Orderby算法,能夠直接按頻率和字典序輸出結果)
PS:增長客服需求新功能時,只需將一些變量變成由客戶輸入便可。
6、代碼規範與互審
代碼規範:
二、不變的值,儘可能寫個常量類。
三、儘可能使用if{}else,不要一直if去判斷。
四、減小循環調用方法;減小IO流的消耗資源。
5. 當一行代碼太長時,將其截斷成兩行寫。
6. 經常使用縮進和換行,使代碼層次清晰,明瞭。
7. 註釋的量不該該少於代碼量的三分之一。ps(變量統一使用例如/// <param name="s">文件讀入路徑</param>的註釋方式)
8. 定義變量名字和方法名字的時候儘可能使用英文縮寫,或者拼音縮寫,便於識別。
9. 對泛型進行循環時,都採用foreach而不使用for。
11. 對於功能函數寫入一個function文件夾中,便於之後功能升級。
12. 一屏原則:一個方法體的代碼幅應該在一屏比較和合理;邏輯複雜的代碼能夠抽離出方法體;
(這只是一部分,固然還有不少,就不一一列舉了)
代碼互審:
在編寫統計字符個數時,最初代碼以下:
public static int agefile()//打開文件並統計字符個數 { string fileName = @"D:\新建文本文檔 (3).txt"; FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read); byte[] buf = new byte[fs.Length]; fs.Read(buf, 0, buf.Length); fs.Close(); return buf.Length; }
通過代碼複審後,發現打開文件和統計字符個數時過於繁雜,便有了如下代碼:這樣一來,代碼精簡不少,佔用空間更少。
public static int agefile()//打開文件並統計字符個數 { string str = File.ReadAllText(@"C:\Users\LiuQi\Desktop\新建本文檔案(3).txt"); int num = Regex.Matches(str, @".").Count; return num + lines() - 1; }
其次,在統計單詞出現頻率和按要求輸出時時,最開始傻傻的認爲按需求一步步編寫代碼就能解決。可是實際操做起來卻
發現存在不少問題,許多簡單狀況下可以操做,在複雜狀況下,存在不少不少的限制,不能輕易解決。
例如:在按字典表輸出時,按原思路就是按順序判斷而後輸出,作到一半都發現太麻煩了,就去百度了一下有沒有簡單算法,
便發現C#自帶字典數排序,只需調用便可。
7、模塊接口部分的性能改進
一、改進計算模塊性能上所花費的時間:45分鐘
2.、改進思路:將統計行數,字符數的函數封裝成一個類,到時候能夠根據用戶需求只需改變參數便可。
三、耗時最多的函數:(運用字典數統計字符總數和其出現的頻率)
public static Dictionary<string, int> Countword() { string str = File.ReadAllText(@path.s); Dictionary<string, int> frequencies = new Dictionary<string, int>(); string[] words = Regex.Split(str, @"\W+"); int k = 0; string[] newwords = ynword.ynword1(words,ref k); string[] newwords1 = new string[k]; for (int i = 0; i < k; i++) { newwords1[i] = newwords[i]; } foreach (string word in newwords1) { if (frequencies.ContainsKey(word)) { frequencies[word]++; } else { frequencies[word] = 1; } } return frequencies; }
8、單元測試與部分異常處理
在沒有對函數進行封裝時,咱們對各自對對方寫的代碼進行了單元測試
一、首先針對邏輯上第一個調用的計算行數的功能模塊linescount進行測試(函數以下):
public class linescountTests { [TestMethod()] public void linesTest() { path.s = @"D:\se.txt"; int x = 0;//第一次測試時輸入5,第二次輸入0 Assert.AreEqual(x, linescount.lines()); // Assert.Fail(); } }
測試結果:第一次在記事本輸入兩行測試成功,但在輸入0行時,測試失敗。此處出現問題,當沒有輸入文本時,行數沒有進行判斷,因此出現錯誤。
2.測試asccount類(統計有多少個字符)封裝的類以下:
public class asccountTests { [TestMethod()] public void asccountsTest() { path.s = @"D:\se.txt"; int num = 8; Assert.AreEqual(num, asccount.asccounts()); //Assert.Fail(); } }
測試結果:當文本不輸入字符時,num=0,出現錯誤。思考後,發現是沒有判斷爲0的狀況,出現錯誤。
3.其他類通過測試並未發生什麼問題。
4.功能改進後的主函數:
static void Main(string[] args) { int temp = 0; int max = 0; int len = 0; //若是命令行有參數執行 if (args.Count() != 0) { for (int i = 0; i < args.Length; i++) { if (args[i] == "-i") path.s = args[++i];//-i 命令行 else if (args[i] == "-n") max = Convert.ToInt32(args[++i]);//-n 命令行 else if (args[i] == "-o") path.outputpath = args[++i];//-o 命令行 else if (args[i] == "-m") { len = Convert.ToInt32(args[++i]); } } if (path.s == null || path.outputpath == null)//路徑爲空則不存在 { Console.WriteLine("路徑不正確,文件不存在"); } } //命令行無參數,執行 else { Console.WriteLine("不輸入參數,請手動輸入讀入文件路徑"); string s= Console.ReadLine(); path.s = s; max = 10; Console.WriteLine("請手動輸入輸出路徑"); string s1 = Console.ReadLine(); path.outputpath = s1; } Dictionary<string, int> frequencies = function.wordcount.Countword();//調用wordcount中方法統計單詞 Dictionary<string, int> dic1Asc = frequencies.OrderBy(o => o.Key).ToDictionary(o => o.Key, p => p.Value);//按照字典序進行排序 int sum = function.wordcount.sum1(dic1Asc);//計算出單詞總數量 Console.WriteLine("字符數:"+asccount. asccounts());//計算出字符數量 Console.WriteLine("單詞總數:" + sum); Console.WriteLine("行數:"+linescount. lines());//計算出行數 //先按照出現次數排序,若是次數相同按照字典序排序 Dictionary<string, int> dic1Asc1 = frequencies.OrderByDescending(o => o.Value).ThenBy(o => o.Key).ToDictionary(o => o.Key, p => p.Value); foreach (KeyValuePair<string, int> entry in dic1Asc1) { if (temp == max) break; string word = entry.Key; int frequency = entry.Value; temp++; Console.WriteLine("{0}:{1}", word, frequency); } Console.ReadKey(); }
9、心路歷程與收穫
首先此次的做業因爲已經有了上次Github的操做經驗,再一次使用時,以爲不在陌生,基礎操做都可以完成。在說說代碼,初一看感受並非很難,可是在
實際操做過程當中,倒是發現存在各類各樣的小問題。(結對編程時,兩人對換行符所佔字符數發生了奇異,改來改去,發現最開始的代碼是對的,而從新寫的
代碼也是對的,白白的糾結了不少時間。)有些小問題是編寫代碼時發生的,有些倒是知識點漏區產生的。隨後就在這些小問題中,浪費了打把的時間,可是
我的看來,效率仍是遠遠大於單人操做。編寫代碼時,同伴會在一旁發表本身的看法,也會幫忙指出忽略的錯誤之處,大大提升了效率,所以我以爲1+1>2。