2017-04-12 178 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

相關問題