2015-04-30 19 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