嵌套循环功能需要几分钟才能运行,无论如何要提高效率?

时间:2015-01-29 17:59:33

标签: c# arrays performance loops jagged-arrays

我知道这个功能会包含大量的数据处理功能,但我认为它最终不会采用小步小麦进行处理。

所讨论的函数由锯齿状2D阵列提供,该阵列由段落>组成。句子是由用户提供的文本文件制作的,因此可能很大。它采用这个数组并将每个句子相互比较并保存每个句子之间的分数,即每个常用单词的数量。

这需要永远,我真的没想到会这样。

我的主要测试文本长度只有181个句子,但这相当于在2D数组中得分的32.7千个值。

然后使用这个值矩阵来计算和选择最相关的"每个段落中的句子以及其他内容。

181句话文本需要1分15秒才能处理,只有70个句子的文字需要35秒,但这是基于句子的数量而不是单词,但它会给你一个想法。我不敢想想实际文件需要多长时间。

有问题的功能:

    protected void Intersection2DArray()
    {
        mainSentenceCoord = -1;
        for (int x1 = 0; x1 < results.Length; x1++)
        {
            for (int x2 = 0; x2 < results[x1].Length; x2++)
            {
                var mainSentencesWords = wordSplit(results[x1][x2]);
                secondarySentenceCoord = -1;
                mainSentenceCoord++;

                for (int y1 = 0; y1 < results.Length; y1++)
                {
                    for (int y2 = 0; y2 < results[y1].Length; y2++)
                    {
                        var secondarySentencesWords = wordSplit(results[y1][y2]);
                        int commonElements = mainSentencesWords.Intersect(secondarySentencesWords).ToList().Count();
                        secondarySentenceCoord++;
                        intersectionArray[mainSentenceCoord, secondarySentenceCoord] = commonElements;
                    }
                }
            }
        }
    }

wordSplit函数:

        protected List<String> wordSplit(string sentence)
        {
            var symbols = "£$€#&%+-.";
            var punctuationsChars = Enumerable.Range(char.MinValue, char.MaxValue - char.MinValue)
                                        .Select(i => (char)i)
                                        .Where(c => char.IsPunctuation(c))
                                        .Except(symbols)
                                        .ToArray();

            var words = sentence.Split(punctuationsChars)
                             .SelectMany(x => x.Split())
                             .Where(x => !(x.Length == 1 && symbols.Contains(x[0])))
                             .Distinct()
                             .ToList();
            return words;
        }

我最初想要使用一个Regex系列进行拆分,但不会弄清楚,这可能会使它更快。

这循环选择每个句子相互对立,这是最好的我可以出现。如果能够大幅度提高速度的话,我总体上做得很好。

编辑:使用Moby Disk建议继承我的新即时代码:

Word分割功能,现在调用一次并返回List列表

    public List<List<string>> createWordList()
    {
        List<List<string>> wordList = new List<List<string>>();
        var symbols = "£$€#&%+-.";
        var punctuationsChars = Enumerable.Range(char.MinValue, char.MaxValue - char.MinValue)
                                    .Select(i => (char)i)
                                    .Where(c => char.IsPunctuation(c))
                                    .Except(symbols)
                                    .ToArray();

        for (int x1 = 0; x1 < results.Length; x1++)
        {
            for (int x2 = 0; x2 < results[x1].Length; x2++)
            {
                var words = results[x1][x2].Split(punctuationsChars)
                                            .SelectMany(x => x.Split())
                                            .Where(x => !(x.Length == 1 && symbols.Contains(x[0])))
                                            .Distinct()
                                            .ToList();
                wordList.Add(words);                    
            }
        }
        return wordList;
    }

现在超薄的交叉功能

    protected void intersectionMatrix()
    {
        List<List<string>> wordList =  createWordList();
        mainSentenceCoord = -1;
        for (var x = 0; x < wordList.Count; x++)
        {
            secondarySentenceCoord = -1;
            mainSentenceCoord++;
            for (var y = 0; y < wordList.Count; y++)
            {
                secondarySentenceCoord++;
                intersectionArray[mainSentenceCoord, secondarySentenceCoord] = wordList[x].Intersect(wordList[y]).Count();
            }
        }
    }

1 个答案:

答案 0 :(得分:4)

请参阅最后的更新:

这里有一些“悬而未决的果实”可以通过更改算法本身来加快速度:

  1. wordSplit()每次调用时都会重新计算“punctuationsChars”。做到这一点。
  2. 你正在为同一个句子调用wordSplit()N ^ 2次而不是N次,因为它在外(x1,x2)循环和内(y1,y2)循环中。你只需要拆分181个句子,而不是181 ^ 2个句子。因此,循环遍历结果,在每个句子上调用wordSplit一次,并存储该结果。如果这会占用太多内存,请查看memoization(http://en.wikipedia.org/wiki/Memoization),虽然我认为你应该没问题,因为它只会产生大约1份文本副本。
  3. 在Intersect()之后不需要ToList()。这会创建一个您不使用的列表。
  4. 我对mainSentenceCoord和secondarySentenceCoord的值感到困惑。生成的intersectionArray的维数是什么?

    天啊!#1就是它!这加快了80倍。看看这一行:

    Enumerable.Range(char.MinValue, char.MaxValue - char.MinValue)
    

    char.MaxValue为65536.因此,如果N = 181,则循环181 x 181 x 65536!我刚刚运行了探查器来确认它:98.4%的CPU时间花费在wordSplit的ToArray()调用中。