使用Python识别对象数组中重复模式的最有效方法是什么

时间:2017-02-14 00:04:14

标签: python arrays pattern-matching

我有两个5个对象的数组

  

a = ['a','b','c','d','e','f','e','f']

     

b = ['a','b','d','f','e','f']

我想确定多个对象的重复模式及其出现情况,如

  

['a','b']:2

     

['e','f']:3

     

['f','e','f']:2

第一个序列['a','b']在a中出现一次,在b中出现一次,因此总计数为2.第二个序列['e','f']在a中出现两次,一次出现在b中,所以总数为3.第3个序列['f','e','f']在a中出现一次,在b中出现一次,所以总数为2.

在Python中有一个很好的方法吗?

对象的范围也是有限的。想知道是否有一个使用哈希表的有效解决方案?

2 个答案:

答案 0 :(得分:2)

如果方法仅针对两个列表,则以下方法应该有效。我不确定这是否是最有效的解决方案。

this blog post中给出了查找n-gram的一个很好的描述。

此方法提供最小长度并确定列表的重复序列可能具有的最大长度(最多为列表长度的一半)。

然后,我们通过组合各个列表的序列找到每个列表的所有序列。然后我们有一个每个序列及其计数的计数器。

最后,我们返回一个不止一次出现的所有序列的字典。

def find_repeating(list_a, list_b):
    min_len = 2

    def find_ngrams(input_list, n):
        return zip(*[input_list[i:] for i in range(n)])

    seq_list_a = []
    for seq_len in range(min_len, len(list_a) + 1):
        seq_list_a += [val for val in find_ngrams(list_a, seq_len)]

    seq_list_b = []
    for seq_len in range(min_len, len(list_b) + 1):
        seq_list_b += [val for val in find_ngrams(list_b, seq_len)]

    all_sequences = seq_list_a + seq_list_b

    counter = {}
    for seq in all_sequences:
        counter[seq] = counter.get(seq, 0) + 1

    filtered_counter = {k: v for k, v in counter.items() if v > 1}

    return filtered_counter

如果您对任何事情不确定,请告诉我。

>>> list_a = ['a', 'b', 'c', 'd', 'e', 'f', 'e', 'f'] 
>>> list_b = ['a', 'b', 'd', 'f', 'e', 'f']
>>> print find_repeating(list_a, list_b)
{('f', 'e'): 2, ('e', 'f'): 3, ('f', 'e', 'f'): 2, ('a', 'b'): 2}

答案 1 :(得分:1)

当您提到您正在寻找高效解决方案时,我首先想到的是解决longest common subsequence problem的方法。但在你的情况下,我们确实需要枚举所有常见的子序列,以便我们可以对它们进行计数,因此动态编程解决方案不会这样做。这是我的解决方案。它肯定比SSSINISTER的解决方案更短(主要是因为我使用collections.Counter类)。

#!/usr/bin/env python3

def find_repeating(sequence_a, sequence_b, min_len=2):
    from collections import Counter

    # Find all subsequences
    subseq_a = [tuple(sequence_a[start:stop]) for start in range(len(sequence_a)-min_len+1) 
        for stop in range(start+min_len,len(sequence_a)+1)]
    subseq_b = [tuple(sequence_b[start:stop]) for start in range(len(sequence_b)-min_len+1) 
        for stop in range(start+min_len,len(sequence_b)+1)]

    # Find common subsequences
    common = set(tup for tup in subseq_a if tup in subseq_b)

    # Count common subsequences
    return Counter(tup for tup in (subseq_a + subseq_b) if tup in common)

导致......

>>> list_a = ['a', 'b', 'c', 'd', 'e', 'f', 'e', 'f'] 
>>> list_b = ['a', 'b', 'd', 'f', 'e', 'f']
>>> print(find_repeating(list_a, list_b))
Counter({('e', 'f'): 3, ('f', 'e'): 2, ('a', 'b'): 2, ('f', 'e', 'f'): 2})

使用collections.Counter的优势在于,您不仅无需生成实际代码进行迭代和计数,还可以访问所有dict方法以及一些专门方法使用这些计数。