2017-04-12 80 views
0

我有一个读取100个文本文件的项目,其中包含5000个单词。在c#中并行读取和处理100个文本文件

我将单词插入到列表中。我有第二个包含英语停用词的列表。我比较两个列表并删除第一个列表中的停用词。

需要1个小时,运行应用程序。我想将它并行化。我怎样才能做到这一点?

继承人我的代码:

private void button1_Click(object sender, EventArgs e) 
    { 

     List<string> listt1 = new List<string>(); 
     string line; 

     for (int ii = 1; ii <= 49; ii++) 
     { 

      string d = ii.ToString(); 
      using (StreamReader reader = new StreamReader(@"D" + d.ToString() + ".txt")) 

      while ((line = reader.ReadLine()) != null) 
      { 

       string[] words = line.Split(' '); 
       for (int i = 0; i < words.Length; i++) 
       { 
        listt1.Add(words[i].ToString()); 



       } 
      } 

      listt1 = listt1.ConvertAll(d1 => d1.ToLower()); 

      StreamReader reader2 = new StreamReader("stopword.txt"); 
      List<string> listt2 = new List<string>(); 
      string line2; 
      while ((line2 = reader2.ReadLine()) != null) 
      { 
       string[] words2 = line2.Split('\n'); 
       for (int i = 0; i < words2.Length; i++) 
       { 
        listt2.Add(words2[i]); 

       } 
       listt2 = listt2.ConvertAll(d1 => d1.ToLower()); 

      } 

      for (int i = 0; i < listt1.Count(); i++) 
      { 
       for (int j = 0; j < listt2.Count(); j++) 
       { 
        listt1.RemoveAll(d1 => d1.Equals(listt2[j])); 

       } 
      } 
      listt1=listt1.Distinct().ToList(); 


      textBox1.Text = listt1.Count().ToString(); 
     } 
    } 
    } 
} 
+0

如果需要很长时间才能运行,则会出现问题。 – jdweng

+0

我做了两个文件,列表数目是1780现在我做了49个文件和它的35分钟运行 – user3903589

+0

两个文件运行需要多长时间? – jdweng

回答

2

我固定的许多事情与你的代码。我不认为你需要多线程:

private void RemoveStopWords() 
    { 
     HashSet<string> stopWords = new HashSet<string>(); 

     using (var stopWordReader = new StreamReader("stopword.txt")) 
     { 
      string line2; 
      while ((line2 = stopWordReader.ReadLine()) != null) 
      { 

       string[] words2 = line2.Split('\n'); 
       for (int i = 0; i < words2.Length; i++) 
       { 
        stopWords.Add(words2[i].ToLower()); 
       } 
      } 
     } 

     var fileWords = new HashSet<string>(); 

     for (int fileNumber = 1; fileNumber <= 49; fileNumber++) 
     {    
      using (var reader = new StreamReader("D" + fileNumber.ToString() + ".txt")) 
      { 
       string line; 
       while ((line = reader.ReadLine()) != null) 
       { 
        foreach(var word in line.Split(' ')) 
        { 
         fileWords.Add(word.ToLower()); 
        } 
       } 
      } 
     } 

     fileWords.ExceptWith(stopWords); 

     textBox1.Text = fileWords.Count().ToString(); 


    } 

您通过禁用词很多次,以及不断添加到列表中,并重新尝试并卸下同一禁用词列表由于再次阅读你的代码结构化的方式。您的需求也更好地匹配HashSet而不是List,因为它已经设置了基于操作和唯一性的处理。

如果你仍然想使这个并行,您可以通过一次读取停止字列表,并将其传递给异步方法,将读取输入文件,删除停用词,并返回结果列表做到这一点,那么你就需要在异步调用返回之后合并结果列表,但在决定需要之前,您最好测试一下,因为这比代码已经有了更多的工作和复杂性。

+0

我也想建议OP了解大O记法算法复杂度:这里的wiki链接https://en.wikipedia.org/wiki/Big_O_notation。了解循环操作和其他算法如何运行以更好地优化程序是很好的。 – jg943

+0

tnx为你的帮助多数民众赞成我的工作! – user3903589

1

一个问题我在这里看到的,它可以帮助提高性能listt1.ConvertAll()将在O(n)的名单上运行。您已经循环添加项目到列表中,为什么不将它们转换为小写。另外为什么不把这些单词存储在一个哈希集合中,所以你可以在O(1)中查找和插入。您可以将停用词列表存储在散列集中,当您正在读取文本输入时,请查看该词是否是停用词,以及是否将其添加到散列集以输出用户。

+0

我在5分钟前添加了一个答案,完成所有这些。他还多次阅读停用词列表,并不断将其添加到从一开始就检查的单词列表中,而不仅仅是他在迭代中添加的那些单词。 – wllmsaccnt

+1

Aww男人只是错过时机哈哈感谢张贴与代码的答案。 – jg943

+0

好的建议TNX – user3903589

1

如果我理解正确的话,你想:

  1. 从文件中读取所有单词到列表
  2. 从名单上的99多个文件全部删除“停止词”
  3. 重复,只保存唯一的话

如果这是正确的,代码非常简单:

// The list of words to delete ("stop words") 
var stopWords = new List<string> { "remove", "these", "words" }; 

// The list of files to check - you can get this list in other ways 
var filesToCheck = new List<string> 
{ 
    @"f:\public\temp\temp1.txt", 
    @"f:\public\temp\temp2.txt", 
    @"f:\public\temp\temp3.txt" 
}; 

// This list will contain all the unique words from all 
// the files, except the ones in the "stopWords" list 
var uniqueFilteredWords = new List<string>(); 

// Loop through all our files 
foreach (var fileToCheck in filesToCheck) 
{ 
    // Read all the file text into a varaible 
    var fileText = File.ReadAllText(fileToCheck); 

    // Split the text into distinct words (splitting on null 
    // splits on all whitespace) and ignore empty lines 
    var fileWords = fileText.Split(null) 
     .Where(line => !string.IsNullOrWhiteSpace(line)) 
     .Distinct(); 

    // Add all the words from the file, except the ones in 
    // your "stop list" and those that are already in the list 
    uniqueFilteredWords.AddRange(fileWords.Except(stopWords) 
     .Where(word => !uniqueFilteredWords.Contains(word))); 
} 

这可以聚焦成一行,没有显式循环:

// This list will contain all the unique words from all 
// the files, except the ones in the "stopWords" list 
var uniqueFilteredWords = filesToCheck.SelectMany(fileToCheck => 
    File.ReadAllText(fileToCheck) 
     .Split(null) 
     .Where(word => !string.IsNullOrWhiteSpace(word) && 
         !stopWords.Any(stopWord => stopWord.Equals(word, 
          StringComparison.OrdinalIgnoreCase))) 
     .Distinct()); 

此代码处理超过100的文件与每个超过12000分的话在不到一秒钟(WAY不到一秒... 0.0001782秒)

+0

我试图让他的代码结构在我的解决方案,但我喜欢你的好。今天我学到了什么.Split(null)的确如此(尽管没有人会原谅那种调用约定)。您也可以将StringSplitOptions.None传递给split方法,并且可以让您在where子句中放弃IsNullOrWhitespace调用。 – wllmsaccnt

+0

@wllmsaccnt是的,但是这个选项在传递'null'时不可用 - 你必须传递一个你想分割的空白字符数组(这很好) –

+0

tnx你的帮助 – user3903589

相关问题