LINQ查找部分匹配

时间:2012-04-18 01:03:11

标签: .net linq

来自OCR的单词并需要一个紧密匹配的列表。 可以没有maxFrom。 示例代码是强力的,但希望它定义了要求。 对于600,000的名单,这需要2秒。 FTSword.Word是一个字符串。

理想情况下,“找到”只会给第二个d带来额外的功劳。一旦它找到了我,那么f就没有信用。蛮力我能做到这一点。我希望减少2秒钟。将测试并报告任何提议的解决方案。

问题??是。如何让它更快? (而且更聪明)

由于

            char[] find = new char[] { 'f', 'i', 'n', 'd' };
            char[] word;
            int maxFrom = 10;
            int minMatch = 3;
            int count;
            List<FTSword> matchWords = new List<FTSword>();
            foreach (FTSword ftsw in fTSwords)
            {
                if (ftsw.Word.Length < maxFrom)
                {
                    word = ftsw.Word.ToCharArray();
                    count = 0;
                    foreach (char fc in find)
                    {
                        foreach (char wc in word)
                        {
                            if (char.ToLower(wc) == char.ToLower(fc))
                            {
                                count++;
                                break;
                            }
                        }
                    }
                    if (count >= minMatch)
                    {
                        // Debug.WriteLine(count.ToString() + ftsw.Word);
                        matchWords.Add(ftsw);
                    }
                }
            }
            Debug.WriteLine(matchWords.Count.ToString());

2 个答案:

答案 0 :(得分:1)

您的核心算法目前是O(n ^ 2),因为您有两个嵌套循环来查找匹配的字符。您可以使用包含find字符串中每个字符的字符数的字典轻松地创建该部分O(n):

string find = "find";
var findMap = new Dictionary<char, int>();
foreach (char c in find)
{
    if (findMap.ContainsKey(c))
    {
        findMap[c] = findMap[c] + 1;
    }
    else
        findMap.Add(c, 1);
}
//findMap is pre-generated once

string word = "pint";
int count = 0;

//runs for each word in list, now in O(n)
foreach(char c in word)
{
    int charCount;
    if(findMap.TryGetValue(c, out charCount))
    {
        if(charCount > 0)
        {
            charCount--;
            findMap[c] = charCount;
            count++;
        }
    }
}

答案 1 :(得分:1)

如果你确定在开始之前它是低位的,你可以删除fc上的char.ToLower()

您也可以尝试使用IndexOf()查找第一个(然后是后续出现的字符),因为BCL实现可能在内部比您自己的循环管理更快。

您也可以尝试反向运行循环,这可以提供加速:

 for (int i = arr.Length - 1; i >= 0; i--)

但实际上,对于OCR,为什么要总结字符串中任意位置的匹配字符,而不是像Damerau-Levenshtein那样进行真正的编辑距离?