【问题标题】:why this loop is running so slowly: c#为什么这个循环运行如此缓慢:c#
【发布时间】:2013-10-26 11:21:55
【问题描述】:

所以我正在做一个文本挖掘项目,目前正在尝试实现信息增益。我有一个数据,其中每一行都描绘了一个文档。所以换行符会分割不同的文档。

我必须生成一个矩阵,其中列是所有文档中的所有不同单词,行是不同的文档。此表中的每个单元格为 1(真)或 0(假),用于判断该文档中是否存在该单词。 有 987 个文档,总词数为 22860,总不同词数为 3680。因此将 3680 个词与 22860 进行比较。这运行缓慢,但很好。花费更多时间的循环是当我遍历单词列表的对象以生成矩阵时。见下文

注意:我已经删除了文档中所有重复的单词。

 class word_list
        {
            public string word;
            public List<bool> doc= new List<bool>();
        };//class ends

        private void button2_Click(object sender, EventArgs e)
        {
            //Convert the string into an array of words 
            string[] w1 = richTextBox1.Text.Trim().Split('\n',' ').Select(x => x.Trim().ToLower()).Distinct().ToArray(); //all distinct words
            string[] rich_doc = richTextBox1.Text.Trim().Split('\n'); //all documents array
            List<word_list> words = new List<word_list>();

            richTextBox2.Text+=("no. of distict words: " + w1.Length + ", no. of docs " + rich_doc.Length);
            for (int i = 0; i < w1.Length; i++)
            {
                word_list temp = new word_list();
                temp.word = w1[i]; //temp has the current distict word as class object

                for(int j=0;j<rich_doc.Length;j++)//traverse all doc array
                {
                    temp.doc.Add(false);
                    List<string> doc_word = Regex.Split(rich_doc[j], @"\b").Distinct(StringComparer.CurrentCultureIgnoreCase).ToList();
                    //richTextBox2.Text += ("\n no. of words in this doc: " + doc_word.Count);
                    //richTextBox2.SelectionStart = richTextBox1.Text.Length;
                    //richTextBox2.Focus();
                    int doc_count = doc_word.Count; // number of docs
                    for (int k = 0; k < doc_count; k++)//All words in a doc are compared
                    {
                        if(doc_word[k].ToLower() == w1[i].ToLower())
                        {
                            temp.doc[temp.doc.Count-1]=true;                            
                            break;
                        }
                    }                      
                }
                if ((words.Count - 1)>=0)
                    richTextBox2.Text += ("\n word(" + words.Count + "/" + w1.Length + "): " + words[words.Count - 1].word);
                richTextBox2.SelectionStart = richTextBox1.Text.Length;
                richTextBox2.Focus();
                words.Add(temp);
            }
            //generate matrix
            int t = rich_doc.Length; //no. of docs
            int word_count = words.Count;
            richTextBox1.Text = "Doc";
            foreach (word_list w in words)
            {
                richTextBox1.Text += "\t" + w.word;
            }
            richTextBox1.Text += "\n";
//This loop is slow
            for (int i = 0; i < t; i++) //traverse through number of docs
            {
                richTextBox1.Text += i + 1;
                for (int h = 0; h < word_count; h++)//traverse through each distinct word in the list
                {
                    if (words[h].doc[i])
                        richTextBox1.Text += "\t1";
                    else
                        richTextBox1.Text += "\t0";
                }
                richTextBox1.Text += "\n";
            }
        }//end of button 2

【问题讨论】:

  • mediafire.com/?4mojnj4j153q76s :这是正在处理的数据,richtextbox2 用于测试目的
  • 考虑使用StringBuilder 来构建字符串,而不是使用TextBox.Text 作为工作空间。

标签: c# performance list loops


【解决方案1】:

ta.speot.is 是正确的。字符串应该使用StringBuilder 构建,例如使用Append,并且只有在循环之后才将字符串分配给richTextBox1.Text。代码如下所示:

        //generate matrix
        StringBuilder sb = new StringBuilder();
        int t = rich_doc.Length; //no. of docs
        int word_count = words.Count;
        richTextBox1.Text = "Doc";
        foreach (word_list w in words)
        {
            sb.Append("\t");
            sb.Append(w.word);
        }
        sb.AppendLine();

        //This loop is not slow anymore :)
        for (int i = 0; i < t; i++) //traverse through number of docs
        {
            sb.Append(i + 1);
            for (int h = 0; h < word_count; h++)//traverse through each distinct word in the list
            {
                if (words[h].doc[i])
                    sb.Append("\t1");
                else
                    sb.Append("\t0");
            }
            sb.AppendLine();
        }
        richTextBox1.Text = sb.ToString();

编辑:下面有有价值的 cmets。更改RichEditBox.Text 属性是这里最昂贵的操作。

【讨论】:

  • 现在试试
  • 与不使用richTextBox1.Text 相比,StringBuilder 可能是一个微不足道的优化。设置Text 将启动各种处理。
  • 他使用string+=的事实可能没有他使用richTextBox.Text+=的事实那么痛苦;)当然字符串添加比StringBuilder.Append慢得多,但是设置文本并且在屏幕上中继/重绘文本甚至更慢! (虽然 RTBox 可能不会立即重绘,但它仍然会强制无效和许多不必要的重绘。)
  • @quetzalcoatl 是的,我已经注意到了。
  • @ta.speot.is - 是的,我看到你比我快 10 秒 :) 但实际上我想暗示 Dialecticus 在他的回答中包含实际问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-11
  • 2012-10-02
  • 1970-01-01
  • 1970-01-01
  • 2021-05-03
  • 1970-01-01
相关资源
最近更新 更多