【问题标题】:Is there a faster way to find repeated patterns in a list?有没有更快的方法来查找列表中的重复模式?
【发布时间】:2020-04-13 14:33:54
【问题描述】:

这里是 Python 新手。我有一个问题,我想在一个列表中找到所有重复的模式(特别是在我的情况下,它是一个整数列表)。因此,例如,给定列表 [2,1,4,3,12,8,3,3,4,16,2,9,9,8,3,3,4,1,4,3,4 ,8,3,3,4] 并且最小模式长度为 3,算法会发现 [8,3,3,4] 出现三次,[1,4,3] 出现两次(也很高兴有索引所有出现)。

我有一些可以工作的代码,虽然有点笨拙,但我希望最终使用这些代码的列表可能非常大。我不太确定如何计算代码的操作复杂性,但我知道当我使用大型列表时它肯定会变得非常慢。

我的问题是,有没有人知道的更好的算法可以做到这一点,和/或我是否以非常低效的方式做到这一点?感谢您能给我的任何帮助。

代码如下:

# Searches list to determine how many times small list is included in big list
def contains(small, big):
    counter = 0
    # initiating list of indexes. N.B. indexlist gives LAST index of sequence, not first
    indexlist = []
    for i in range(len(big)-len(small)+1):
        for j in range(len(small)):
            if big[i+j] != small[j]:
                break
        else:
            counter += 1
            indexlist.append(i+j)
    if counter > 0:
        return counter, indexlist
    return False

def findrepeats(sequence, n_letters):
    fulldict = {}
    # Iterating through all the short-sequences of n letters in the list
    for i in range(0, len(sequence) - n_letters):
        shortliststr = ""
        shortlist = sequence[i:i + n_letters]
        for number in shortlist:
            shortliststr = shortliststr + "." + str(number)
        # If short-sequence is found in full sequence more than once (i.e. itself), add to dict
        if contains(shortlist, sequence)[0] > 1 and len(shortlist) == n_letters:
            fulldict[shortliststr] = contains(shortlist, sequence)
    return fulldict

def findallrepeats(sequence, min_letters, max_letters):
    fulldict = {}
    # Iterating through all possible n_letters in findrepeats() between given range
    for i in range(min_letters, max_letters):
        newdict = findrepeats(sequence, i)
        fulldict.update(newdict)
    return fulldict

【问题讨论】:

标签: python list algorithm


【解决方案1】:

重叠

您可以使用大小为 n = 3 的滑动窗口来迭代您的序列并计算此窗口的出现次数。

使用more_itertools

例如:

import collections
import more_itertools

sequence = [
    2, 1, 4, 3, 12, 8, 3, 3, 4, 16, 2, 9, 9,
    8, 3, 3, 4, 1, 4, 3, 4, 8, 3, 3, 4,
]
size = 3
windows = [
    tuple(window)
    for window in more_itertools.windowed(sequence, size)
]
counter = collections.Counter(windows)
for window, count in counter.items():
    if count > 1:
        print(window, count)

你得到:

(1, 4, 3) 2
(8, 3, 3) 3
(3, 3, 4) 3

【讨论】:

  • 谢谢!这成功了。在 30,000 个元素的列表中,我的旧代码需要 4 秒(在一台非常旧的笔记本电脑上),而这将其缩短到 0.02 秒。
猜你喜欢
  • 2022-01-27
  • 2012-11-15
  • 1970-01-01
  • 2015-07-02
  • 1970-01-01
  • 1970-01-01
  • 2012-12-22
  • 1970-01-01
  • 2019-10-09
相关资源
最近更新 更多