【问题标题】:Find Same patterns in lists在列表中查找相同的模式
【发布时间】:2012-02-13 17:30:50
【问题描述】:

假设我们有以下列表:

    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 个列表中看到。

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

【问题讨论】:

  • 你能解释一下规则吗?例如。为什么不是3 -&gt; Journey1, Journey2, Journey4
  • 哦,模式是(序列)=>(要搜索的列表列表)?
  • 我们需要找到从最长到最短的模式,因此首先我选择了 2,3,4,这是在不止一次旅程中看到的最长模式。

标签: c# list pattern-matching


【解决方案1】:

没有预计算和简单的即时搜索:

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 万个等于操作。那是几百毫秒。

这完全取决于什么对您来说“非常快”。如果这太慢了,你将需要一个更复杂的方法......

【讨论】:

  • 这是 n^2 并且它不会创建要查找的模式。只需将模式与列表匹配。这只是工作的一半。
  • 尚不清楚这些模式是否已知或尚未被发现。我假设它们是已知的,因为这个问题给了我们像“1”和“5”这样的“单一”项目模式(并且通过机器学习发现这些模式没有意义)。
  • 非常感谢 Darjan,但正如 jb 所说,它不会创建模式,它应该开始创建模式,为了创建模式,我们有一个简单的角色,每个模式至少应该在一个旅程中看到。在进程结束时,如果某些节点保留在不属于任何模式的列表中,我们会将它们添加为新模式。
【解决方案2】:

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

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

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();
}

你会得到这个结果

编号 1 出现在列表 # 0 2 3 中 编号 2 出现在列表 # 0 1 中 编号 3 出现在列表 # 0 1 3 中 编号 4 出现在列表 # 0 1 3 中 编号 5 出现在列表 # 0 中 编号 6 出现在列表 #1 2 中 编号 7 出现在列表 #1 2 中

列表从零开始编号。

【讨论】:

    【解决方案3】:

    对于蛮力方法,您可以尝试使用polynomial hash-functions 来加速子部分匹配。仍然需要大量的比较,但至少匹配可以几乎是恒定的,而与子序列长度无关。

    【讨论】:

      【解决方案4】:

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

      例如,为列表中的所有子序列构建一个 trie 将允许在与模式长度成正比的时间内查询该列表以获取给定模式。

      【讨论】:

        猜你喜欢
        • 2023-03-08
        • 1970-01-01
        • 2011-03-27
        • 2012-06-03
        • 2019-11-29
        • 1970-01-01
        • 1970-01-01
        • 2014-07-07
        相关资源
        最近更新 更多