IList <t>版本的String.IndexOf(找到一个子串',而不仅仅是一个对象)</t>

时间:2011-08-15 16:05:46

标签: c# .net algorithm

我正在寻找List<T>.IndexOf(List<T>)的实施方案。我只在.NET类库中找到了List<<T>.IndexOf(T)

我有List longListList possibleSubList。我想知道possibleSubList是否可以在longList内找到longList,如果是,则指向System.String.IndexOf

这与 {1, 2, 3, 9, 8, 7}.IndexOf({3, 9, 8}) = 2
{1, 2, 3, 9, 8, 7}.IndexOf({1, 2, 3, 9, 8, 7}) = 0
{1, 2, 3, 9, 8, 7}.IndexOf({2, 9}) = -1 (not found)
的语义基本相同。任何人都知道该怎么称呼它或者是否有一个很好的实现呢?

伪代码示例:
{{1}}

澄清:我已经有了一个简单的实现(两个嵌套for循环),但我的列表相当长,这是一个性能敏感区域。我希望找到比我的~O(m * n)更有效的实现。

3 个答案:

答案 0 :(得分:6)

线性Z-Indexing 可能是目前最快的子列表搜索算法之一,其中模式相同且语料库是动态的,具有真正的O(n)复杂度(使用小字母表,由于ZIndexing提供了大量跳过索引的机会,它的表现比你对O(n)的预期要好得多:

我在中佛罗里达大学的Shaojie Zhang的指导下,在遗传算法课上编写了我的实现。我已经将算法改编为C#,特别是使用泛型IList<T>,如果您决定使用它,请给予信任。这些技术的研究可以here,具体来说,请看一下讲义here

无论如何,我已将代码设为here

查看TestZIndexing.cs内部以获取如何执行搜索的示例(在本例中为字符序列,但使用泛型,您应该能够使用具有相等运算符的任何内容)。

用法很简单:

IEnumerable<int> LinearZIndexer.FindZ<T>(
        IList<T> patternSequence, IList<T> sourceSequence, bool bMatchFirstOnly)
        where T: IComparable;

而且,由于某些DNA是循环的,我有一个循环变体:

IEnumerable<int> LinearZIndexer.FindZCircular<T>(
        IList<T> patternSequence, IList<T> sourceSequence, bool bMatchFirstOnly)
        where T: IComparable;

让我们做得更快:后缀树

或者,如果您希望获得比O(n)更好的性能,则可以使用后缀树获得O(m),其中m是模式列表的大小。当模式改变并且语料库保持不变(与前一种情况相反)时,这种方法有效。查看我为TestSuffixTree.cs贡献的同一个库。这里唯一的区别是你必须提前构建后缀树,所以它肯定是针对大型语料库进行多次模式搜索,但我提供了一个O(n)和Space(n)算法来构建后缀树。 / p>

调用同样简单,同样可以使用提供IComparable的任何内容:

string strTest = "bananabananaorangebananaorangebananabananabananaban";
string[] strFind = {"banana", "orange", "ban"};

// I use char, but you can use any class or primitive that 
// supports IComparable

var tree = new SuffixTree<char>();
tree.BuildTree(strTest.ToCharArray());
var results = tree.Find(str.ToCharArray());
foreach(var r in results) Console.WriteLine(r);

享受。

答案 1 :(得分:1)

使用字符串搜索算法:(伪代码)

findsubstring(list<T> s, list<T> m){
    for(int i=0; i<s.length;++i)
        for(int j=0; j<m.length;++j)
            if(s[i] != s[j])
                break;
            if(j==m.length-1)
                return i;
    return -1;
}

答案 2 :(得分:1)

我认为你使用'sub-string'这个词有点误导。我相信您正在尝试查看较大的列表是否包含与另一个列表中的整个元素序列匹配的元素子序列。如果我理解你想要的东西,这是一个你应该做你想做的扩展方法:

public static int IndexOfSequence<T>(this IEnumerable<T> longL, IEnumerable<T> subL)
    {
        var longList = longL.ToList();
        var subList = subL.ToList();

        int longCount = longList.Count;
        int subCount = subList.Count;

        if (subCount > longCount)
        {
            return -1;
        }

        int numTries = longCount - subCount + 1;

        for (int i = 0; i < numTries; i++)
        {
            var newList = new List<T>(longList.Skip(i).Take(subCount));

            if (newList.SequenceEqual(subList))
            {
                return i;
            }
        }

        return -1;
    }

然后你就可以使用它:

int index = longList.IndexOfSequence(possibleSubList);