摘要:[C#][Winform]GetWords小程式
最近寫了一個支援LearningEnglish的小程式(這篇),其主要的程式碼如下:
List<string> lstSource = new List<string>();
01
public void Convert()
02
{
03
//取得輸入
04
string[] arySource = (!String.IsNullOrEmpty(txtSource.Text.Trim())) ? txtSource.Lines : null;
05
06
if (arySource != null)
07
{
08
for (int i = 0; i < arySource.Length; i++)
09
{
10
//開始切字
11
ParseString(arySource[i]);
12
}
13
lstSource.TrimExcess();
14
//輸出結果
15
txtDestination.Lines = lstSource.ToArray();
16
}
17
}
18
19
public void ParseString(string data)
20
{
21
foreach (Match match in Regex.Matches(data, @"[a-zA-Z]+"))
22
{
23
if (match.Value.Length > 1)
24
lstSource.Add(match.Value.ToLower());
25
}
26
lstSource.Sort();
27
RemoveDuplicate();
28
}
29
30
public void RemoveDuplicate()
31
{
32
int i = 0;
33
while (i < lstSource.Count - 1)
34
{
35
if (lstSource[i] == lstSource[i + 1])
36
lstSource.Remove(lstSource[i + 1]);
37
else
38
i++;
39
}
40
}
public void Convert() 02
{ 03
//取得輸入 04
string[] arySource = (!String.IsNullOrEmpty(txtSource.Text.Trim())) ? txtSource.Lines : null; 05
06
if (arySource != null) 07
{ 08
for (int i = 0; i < arySource.Length; i++) 09
{ 10
//開始切字 11
ParseString(arySource[i]); 12
} 13
lstSource.TrimExcess(); 14
//輸出結果 15
txtDestination.Lines = lstSource.ToArray(); 16
} 17
} 18
19
public void ParseString(string data) 20
{ 21
foreach (Match match in Regex.Matches(data, @"[a-zA-Z]+")) 22
{ 23
if (match.Value.Length > 1) 24
lstSource.Add(match.Value.ToLower()); 25
} 26
lstSource.Sort(); 27
RemoveDuplicate(); 28
} 29
30
public void RemoveDuplicate() 31
{ 32
int i = 0; 33
while (i < lstSource.Count - 1) 34
{ 35
if (lstSource[i] == lstSource[i + 1]) 36
lstSource.Remove(lstSource[i + 1]); 37
else 38
i++; 39
} 40
}這裡會轉成List<String>的原因主要是想利用他的Sort()來排序(懶得自己寫),不過它的效率似乎不是很理想,平均是O(n log n),worst case是O(n2) 。
總覺得程式碼可以再漂亮一些、效能可以再好些,因此開放讓大家來找碴...
10/10/2009 更新:
根據網友larrynung提供的方法,使用List<T>.Contains()的方式可以免除呼叫副程式RemoveDuplicate(),測試結果發現速度稍有提昇:
去NY Times網站copy幾篇文章當作測試來源,先用原始的程式碼測試一遍,關掉程式;用新的程式碼測試一遍,關掉程式。以上方式測試兩次後的結果如下
| 時間 (ms) | 記憶體用量 (MB) | |
| 舊法:第一次 | 6831 | 25 |
| 新法:第一次 | 6618 | 25 |
| 舊法:第二次 | 6833 | 25 |
| 新法:第一次 | 6580 | 25 |
可以發現新法的效能的確稍有提昇,larrynung ![]()
還有人有更好的想法嗎?
10/11/2009 更新:
larrynung又點出兩個盲點:Sort()應該放在副程式的外面 & 正規表示式可以一次全部批配。
所以我先把Sort()移出後得到下面結果
| 時間 (ms) | |
| 第一次 | 127 |
| 第二次 | 127 |
可見這個Sort 擺錯地方影響有多大
之後把逐行批配改成一次全部批配得到如下結果
| 時間 (ms) | |
| 第一次 | 123 |
| 第二次 | 121 |
還可以再次壓榨出效能
最後的code變得非常簡單,也不用再呼叫一些副程式了,如下:
public void Convert()
{
foreach (Match match in Regex.Matches(txtSource.Text, @"[a-zA-Z]+"))
{
if (match.Value.Length > 2 && !lstSource.Contains(match.Value.ToLower()))
lstSource.Add(match.Value.ToLower());
}
lstSource.TrimExcess();
lstSource.Sort();
txtDestination.Lines = lstSource.ToArray();
} 經過這次的討論發現 細心 & 經驗 是這次程式效能校調的關鍵, 要再次給代表大家給提出意見的larrynung一個大拇指![]()
參考:
1. [C#]以列為單位讀取MultiLine TextBox的內容
3. MSDN List<T>.Contains() Method
