如何(快速)在C#/ .Net中找到最长的匹配字符串

时间:2011-11-30 13:08:09

标签: c# collections

我需要对一组项目进行一些查找操作。

首先,我需要看看是否有直接匹配。这很简单,因为我在Dictionary<String,MyObjectType>中有条目,所以我可以去dictionary["valuetofind"]

如果没有直接匹配,那么我需要进行一个启动匹配,但它必须是返回的最长匹配:

记录示例:

String   Record
0        A
01       B
012      D
02       B
03       C

查询示例:

Query         Result 
0             A    - Because 0   is the longest match
01            B    - Because 01  is the longest match
023456        B    - Because 02  is the longest match
012           D    - Because 012 is the longest match
0123456       D    - Because 012 is the longest match
03456         C    - Because 03  is the longest match
04            A    - Because 0   is the longest match
0456          A    - Because 0   is the longest match
1             Null - No Match

框架中是否有类在后台实现中具有哈希或树结构来执行此类操作,或者我是否需要自己编写某些内容?

修改 到目前为止我所拥有的是按照模式字符串的长度排序的列表,然后我逐个查看条目以查看查询是否以记录开头。这适用于大多数情况,因为我们还没有大型列表(但是),但在没有匹配的情况下确实有昂贵的成本。

我缺乏词汇来让google给我一些与哈希集,列表和词典无关的页面。我发现的所有研究都指向基于树的结构,但没有人指出.NET Framework中是否已有实现。

4 个答案:

答案 0 :(得分:8)

Leppie和Spender是正确的;如果数据集变大,你想要有效地解决这个问题的数据结构是“trie”,或者,如果你真的是buff,那么DAWG - 一个有向无环字图。如果字符串有许多常见的后缀但是它们更昂贵且难以构建和更新,那么DAWG具有更好的内存性能,所以从一个特里开始。

你的简单案例会产生一个看起来像这样的特里:

           ROOT
            |
           0|
            |
            A
          / | \
         /  |  \
       1/  2|  3\
       /    |    \
      /     |     \
     B      B      C
     |
    2|
     |
     D

所以要查找023456,你从根开始,沿着标记为0的分支找到A,然后沿着分支2找到B,那时没有分支3,所以你已经完成了。

顺便说一下,这也是你用来找到给定字典和一组字母的最长拼字游戏单词的数据结构;这基本上是同样的问题。

.NET框架中没有内置的数据结构,但构建起来并不困难。我有一个不可改变的特里在我身边的某个地方,我一直想写博客;如果我这样做,我会在这里发布一个链接。

答案 1 :(得分:1)

一种相当简单的方法是brute force他们。我假设您有一个Dictionary<string, string> _lookupTable来保存您的查找

string Find(string query)
{
    var retval = null;
    while(!string.IsNullOrEmpty(query) && retval == null)
    {
        if(!_lookupTable.TryGetValue(query, out retval))
            query = query.Substring(0, query.Length-1);
    }
    return retval;
}

答案 2 :(得分:0)

你可以扫描整个词典以获得最长的匹配。

        string sQuery = "01234";

        int iMaxLength = 0;
        foreach (KeyValuePair<String, String> kVP in mD)
        {
            if (sQuery.Contains(kVP.Value) && (kVP.Value.Length > iMaxLength))
            {
                iMaxLength = kVP.Value.Length
                result = (whatever...)
            }
        }

答案 3 :(得分:0)

从它的外观来看,你应该使用一个二进制树,它只是按长度排序,然后寻找第一个匹配。我不认为二进制树之类的东西已经在c#中实现了,但快速搜索显示了人们已经这样做的许多网站。