Python在大型数字组中查找模式?

时间:2012-07-09 22:05:52

标签: python pattern-matching

我正在使用列表列表,这些列表中的每一个都有非完美平方根的连续分数周期。

我尝试用它们来检查每个列表中最大重复模式的大小。

有些列表例如:

[
 [1,1,1,1,1,1....],
 [4,1,4,1,4,1....],
 [1,2,10,1,2,10....],
 [1,1,1,1,1,4,1,4,1,20,9,8,1,1,1,1,1,4,1,4,1,20,9,8....],
 [2,2,2,4,2,2,2,4....],
 [1,1,1,13,21,45,3,3,1,16,4,1,4,1,1,1,24,15,1,1,1,13,21,45,3,3,1,16,4,1,4,1,1,1,24,15....],
 [1,1,1,3,28,1,1,1,3,28,67,25,1,1,1,3,28,1,1,1,3,28,67,25....]
]

我一直在使用的两种类似方法是:

def lengths(seq):
    for i in range(len(seq),1,-1):
        if seq[0:i] == seq[i:i*2]:
            return i


def lengths(seq):
    for i in range(1,len(seq)-1):
        if seq[0:i] == seq[i:i*2]:
            return i    

这两个都采用列表的大小,并从当前位置比较它的索引大小。 问题是,首先只有一个重复数字返回错误,因为它开始变大,只看到一个大模式。 第二个问题是存在嵌套模式,如第六和第七个示例列表,它将得到满足 使用嵌套循环并忽略模式的其余部分。

5 个答案:

答案 0 :(得分:4)

作品(在样本的第4个元素中发现了拼写错误)

>>> seq_l = [
...  [1,1,1,1,1,1],
...  [4,1,4,1,4,1],
...  [1,2,10,1,2,10],
...  [1,1,1,1,1,4,1,4,1,20,9,8,1,1,1,1,1,4,1,4,1,20,9,8],
...  [2,2,2,4,2,2,2,4,2,2,2,4,2,2,2,4],
...  [1,1,1,13,21,45,3,3,1,16,4,1,4,1,1,1,24,15,1,1,1,13,21,45,3,3,1,16,4,1,4,1,1,1,24,15],
...  [1,1,1,3,28,1,1,1,3,28,67,25,1,1,1,3,28,1,1,1,3,28,67,25]
... ]
>>> 
>>> def rep_len(seq):
...     s_len = len(seq)
...     for i in range(1,s_len-1):
...         if s_len%i == 0:
...             j = s_len/i
...             if seq == j*seq[:i]:
...                 return i
...                 
... 
>>> [rep_len(seq) for seq in seq_l]
[1, 2, 3, 12, 4, 18, 12]

答案 1 :(得分:2)

如果将列表转换为字符串并不可行,那么使用正则表达式会使这个任务变得微不足道。

import re

lists = [
    [1,1,1,1,1,1],
    [4,1,4,1,4,1],
    [1,2,10,1,2,10],
    [1,1,1,1,1,4,1,4,1,20,9,8,1,1,1,1,1,4,1,4,1,20,9,8], #I think you had a typo in this one...
    [2,2,2,4,2,2,2,4],
    [1,1,1,13,21,45,3,3,1,16,4,1,4,1,1,1,24,15,1,1,1,13,21,45,3,3,1,16,4,1,4,1,1,1,24,15],
    [1,1,1,3,28,1,1,1,3,28,67,25,1,1,1,3,28,1,1,1,3,28,67,25]
]

for l in lists:
    s = "x".join(str(i) for i in l)
    print s
    match = re.match(r"^(?P<foo>.*)x?(?P=foo)", s)
    if match:
        print match.group('foo')
    else:
        print "****"
    print

(?P<foo>.*)创建一个名为“foo”的组,(?P=foo)匹配该组。由于正则表达式是贪婪的,因此默认情况下会获得最长匹配。 “x?”只允许中间的单个x处理偶数/奇数长度。

答案 2 :(得分:1)

您可能可以执行collections.defaultdict(int)来保留所有子列表的计数,除非您知道有一些您不关心的子列表。在将子列表作为字典键之前将其转换为元组。

如果空间紧张,你可能会使用一系列布隆过滤器来到某个地方。对于长度为1的子序列,您将有一个布隆过滤器,对于长度为2的子序列,您将有另一个布隆过滤器。然后,获得冲突的最大布隆过滤器具有您的最大长度子列表。

http://stromberg.dnsalias.org/~strombrg/drs-bloom-filter/

答案 3 :(得分:0)

我认为你必须一次检查两个级别的序列。0..i == i..i*20..i/2 != i/2..i

def lengths(seq):
    for i in range(len(seq),1,-1):
        if seq[0:i] == seq[i:i*2] and seq[0:i/2] != seq[i/2:i]:
            return i

如果0..i的两半相等,则表示您实际上是在比较两个连接模式。

答案 4 :(得分:0)

从第一个示例方法开始,您可以递归搜索子模式。

def lengths(seq):
    for i in range(len(seq)-1,1,-1):
        if seq[0:i] == seq[i:i*2]:
            j = lengths(seq[0:i]) # Search pattern for sub pattern
            if j < i and i % j == 0: # Found a smaller pattern; further, a longer repeated
                # pattern length must be a multiple of the shorter pattern length
                n = i/j # Number of pattern repetitions (might change to // if using Py3K)
                for k in range(1, n): # Check that all the smaller patterns are the same
                    if seq[0:j] != seq[j*n:j*(n+1)]: # Stop when we find a mismatch
                        return i # Not a repetition of smaller pattern
                else: return j # All the sub-patterns are the same, return the smaller length
            else: return i # No smaller pattern

我觉得这个解决方案并不完全正确,但我会根据需要进行一些测试和编辑。 (快速注意:不应该在len(seq)-1处开始循环的初始化吗?如果不是,你将seq [0:len]与seq [len:len]进行比较,这看起来很愚蠢,并会导致递归无限循环。)

编辑:似乎排序类似于发布的相关问题发送者中的top answer,因此您最好去阅读。 ;)