在列表中查找相同的模式

时间:2012-02-13 17:30:51

标签: c# list pattern-matching

假设我们有以下列表:

    List<int> Journey1 = new List<int>() { 1, 2, 3, 4, 5 };
    List<int> Journey2 = new List<int>() { 2, 3, 4, 6, 7, 3, 4 };
    List<int> Journey3 = new List<int>() { 6, 7, 1 };
    List<int> Journey4 = new List<int>() { 3, 1, 4 };

模式是:

2, 3, 4 -> Journey1, Journey2;
6, 7    -> Journey2, Journey3;
1       -> Journey2, Journey3, Journey4;
5       -> Journey1;
3, 4    -> Journey2;
3       -> Journey4;
4       -> Journey4;

我们有5000个列表,每个列表大约有200个项目,因此模式可以有1-200个项目,可以在1-5000个列表中看到。

因此我需要非常快速的模式匹配方式。

4 个答案:

答案 0 :(得分:2)

没有预先计算和天真的即时搜索:

var matchedJourneys = journeys.Where(x => ContainsPattern(x, mypattern));

bool ContainsPattern(List<int> list, List<int> pattern)
{
    for(int i = 0; i < list.Count - (pattern.Count - 1); i++)
    {
        var match = true;
        for(int j = 0; j < pattern.Count; j++)  
            if(list[i + j] != pattern[j])
                     {
                         match = false;
                         break;
                     }
        if(match) return true;
    }
    return false;
}

这将执行最多2亿等于检查您的'数字'。但是,由于预计不会对整个模式执行检查,如果检查所有列表,那可能是(仅仅是一个猜测)〜500万等于操作。那是几百毫秒。

这一切都取决于对你来说“非常快”。如果这太慢了,你需要一个更复杂的方法......

答案 1 :(得分:1)

我不确定你想要什么作为输出。我刚试了一次。

我建议您列出一个列表,而不是声明单个列表变量。

List<List<int>> journeys = new List<List<int>>();
journeys.Add(new List<int>() { 1, 2, 3, 4, 5 });
journeys.Add(new List<int>() { 2, 3, 4, 6, 7, 3, 4 });
journeys.Add(new List<int>() { 6, 7, 1 });
journeys.Add(new List<int>() { 3, 1, 4 });

我假设数字范围从0到255.使用此查询

var result = Enumerable.Range(0, 256)
    .Select(number => new
    {
        number,
        listIndexes = journeys
            .Select((list, index) => new { index, list })
            .Where(a => a.list.Contains(number))
            .Select(a => a.index)
            .ToList()
    })
    .Where(b => b.listIndexes.Count > 0)
    .ToList();

和这个测试循环

foreach (var item in result) {
    Console.Write("Number {0} occurs in list # ", item.number);
    foreach (var index in item.listIndexes) {
        Console.Write("{0} ", index);
    }
    Console.WriteLine();
}

你会得到这个结果

    Number 1 occurs in list # 0 2 3 
    Number 2 occurs in list # 0 1 
    Number 3 occurs in list # 0 1 3 
    Number 4 occurs in list # 0 1 3 
    Number 5 occurs in list # 0 
    Number 6 occurs in list # 1 2 
    Number 7 occurs in list # 1 2 

列表从零开始编号。

答案 2 :(得分:0)

对于暴力攻击方法,您可以尝试使用polynomial hash-functions加速子节匹配。仍然需要进行疯狂的比较,但至少匹配可能几乎不变,无论子序列长度如何。

答案 3 :(得分:0)

在您的情况下,有机会受益于模式预处理以及文本预处理(http://en.wikipedia.org/wiki/String_searching_algorithm)。

例如,为列表中的所有子序列构造trie将允许在时间上与模式长度成比例地查询给定模式的列表。