2015-04-30 22 views
1

此方法使用字符串數組中最頻繁的單詞。 對於大型數組,它的工作速度非常緩慢(例如70.000字符串的時間長度爲190.000毫秒)。 我測量(使用秒錶()),它的第一部分是最慢的一個:加速使用c中的大字符串數組工作#

public static List<WordDouble> MostFrequentWords(double count, string[] words) 
    {      
     var wordsAndNumbers = new List<WordDouble>(); 

     foreach (var word in words) 
     { 
      if (wordsAndNumbers.Exists(e => e.Word == word.ToLower())) 
       wordsAndNumbers[wordsAndNumbers.FindIndex(e => e.Word == word.ToLower())].Count++; 
      else 
      { 
       var addWord = new WordDouble(); 
       addWord.Word = word.ToLower(); 
       addWord.Count = 1; 
       wordsAndNumbers.Add(addWord); 
      } 
     }  

/*method goes on, other parts work fast and do not need improvement */ 
... 
return something; 
} 

public class WordDouble 
    { 
     public string Word; 
     public double Count; 
    } 

我怎樣才能改善這種方法的表現呢?

+3

[CodeReview.SE]會您的問題更好的地方。 –

+1

您是否聽說過[Dictionary](https://msdn.microsoft.com/en-us/library/xfhwa508)? – Rawling

+0

不是說它會產生巨大的差異,而是爲'word.ToLower()'創建一個變量,並在使用它的3個位置使用該變量 – Johan

回答

5

在列表中檢查使用Exists的項目是O(n)操作,而檢查字典中的項目是O(1)操作。

這在運行的一小部分時間(實際時間約二千二百分之一):

Dictionary<string, int> wordsAndNumbers = new Dictionary<string, int>(); 

foreach (string word in words) { 
    if (wordsAndNumbers.ContainsKey(word.ToLower())) { 
    wordsAndNumbers[word.ToLower()]++; 
    } else { 
    wordsAndNumbers.Add(word.ToLower(), 1); 
    } 
} 

這裏是70000串試運行的結果是,原代碼,我的代碼和控制檯的代碼,分別爲:

00:01:21.0804944 
00:00:00.0360415 
00:00:00.1060375 

你甚至可以加快它更通過在循環做ToLower只有一次一點點:

var wordsAndNumbers = new Dictionary<string, int>(); 

foreach (var word in words) { 
    string s = word.ToLower(); 
    if (wordsAndNumbers.ContainsKey(s)) { 
    wordsAndNumbers[s]++; 
    } else { 
    wordsAndNumbers.Add(s, 1); 
    } 
} 

試運行:

00:00:00.0235761 
+1

我認爲你應該使用字典構造函數重載女巫採取比較器而不是頻繁的ToLower強制轉換,請檢查我的答案。 – Console

+0

@Console:這是你降低投票的原因嗎? – Guffa

+0

不,我沒有downvote。也許對其他人來說,它是.. – Console

4

首先你爲什麼要使用雙來算的話嗎? 使用一個長的字典,並不會降低只是爲了比較。

Dictionary<string,long> wordsAndNumbers = new 
    Dictionary<string,long>(StringComparer.OrdinalIgnoreCase); 

foreach(var word in words) 
{ 
    if (!wordsAndNumbers.ContainsKey(word)) 
     wordsAndNumbers[word] = 1; 
    else 
     wordsAndNumbers[word]++; 
} 

與70000分的話我得到以下運行時間:00:00:00.0152345這是顯著快那麼這需要00我的機器上,以降低解決方案:00:00.0320127

+0

使用帶比較器的字典的重載看起來不錯,但實際上它慢很多。在我的答案中查看結果。 – Guffa

+1

我用OridinalIgnoreCase比較器替換了CurrentCultureIgnoreCase,在我的機器上,我的實現現在比tolower解決方案快了30% – Console

+0

我認爲你的意思是'OrdinalIgnoreCase'。速度稍快,但我只看到2%的差異。 – Guffa