2010-07-14 45 views
4

我想写一个函数来读取一个文件并计算每个单词出现的次数。假设处理文件读取并产生表示文件中每行的字符串列表,我需要一个函数来计算每个单词的出现次数。首先,是使用Dictionary<string,int>最好的方法?关键是这个词,值是该词出现的次数。这是使用LINQ创建频率表的最佳方式吗?

我写了这个函数遍历在一条线上每一行和每一字,并建立了一个字典:

static IDictionary<string, int> CountWords(IEnumerable<string> lines) 
var dict = new Dictionary<string, int>(); 
foreach (string line in lines) 
{ 
    string[] words = line.Split(' '); 
    foreach (string word in words) 
    { 
     if (dict.ContainsKey(word)) 
      dict[word]++; 
     else 
      dict.Add(word, 1); 
    } 
} 

不过,我想以某种方式写这个功能..功能,使用LINQ(因为LINQ很有趣,我想提高我的函数式编程技巧:d)我设法想出这个expresion,但我不知道它是否做到这一点功能的最佳方式:

static IDictionary<string, int> CountWords2(IEnumerable<string> lines) 
{ 
    return lines 
     .SelectMany(line => line.Split(' ')) 
     .Aggregate(new Dictionary<string, int>(), 
      (dict, word) => 
      { 
       if (dict.ContainsKey(word)) 
        dict[word]++; 
       else 
        dict.Add(word, 1); 
       return dict; 
      }); 
} 

所以虽然我有两个工作解决方案,但我也对lea感兴趣最好采用什么方式来解决这个问题。任何有洞察LINQ和FP的人?

回答

6

蒂姆·罗宾逊写道,你可以使用GroupByToDictionary这样

public static Dictionary<string, int> CountWords3(IEnumerable<string> strings) 
    { 
     return strings.SelectMany(s => s.Split(' ')).GroupBy(w=>w).ToDictionary(g => g.Key, g => g.Count()); 
    } 
+0

从技术上说,这不是通过使用语言集成查询,但通过使用一些扩展方法LINQ是建立在(但是然后OP是要求LINQ,但使用扩展方法,所以这可能是他要求的任何:)) – 2010-07-14 10:37:03

+2

@Rune FS:这一切LINQ,以及个人喜好的问题,无论您使用查询理解语法还是扩展方法语法。 (事实上​​,有些查询只能用扩展方法语法来表示,你会声称这些查询不是LINQ吗?) – LukeH 2010-07-14 10:43:02

+1

@Rune FS:我想他是在寻求像这样的事情。 。正如LukeH指出的那样,这都是LINQ。 – 2010-07-14 10:47:29

3

看看GroupBy而不是Aggregate - 它会给你一组IGrouping<string, string>对象。您可以通过在每个分组上拨打.Count()来检索每个词的计数。

+1

顺便说一句,既然你说你有兴趣学习,我没有发布确切的代码:) – 2010-07-14 10:24:38

+0

谢谢,你的提示帮助我玩更多的东西,得到更好的东西:) – guhou 2010-07-14 11:08:29

3

下应该做的工作。

static IDictionary<String, Int32> CountWords(IEnumerable<String> lines) 
{ 
    return lines 
     .SelectMany(line => line.Split(' ')) 
     .GroupBy(word => word) 
     .ToDictionary(group => group.Key, group => group.Count()); 
} 
0

,如果你想使用LINQ(而不是通过使用LINQ firectly使用的扩展方法),你可以这样写:

var groups = from line in lines 
      from s in line.Split(new []{"\t", " "},StringSplitOptions.RemoveEmptyEntries) 
      group s by s into g 
      select g; 
var dic = groups.ToDictionary(g => g.Key,g=>g.Count()); 

您当前的实现将不会在标签分裂,可能包括“单词“string.Empty所以我已经根据我认为你的意图改变了分裂。