【问题标题】:List pattern finder in python?python中的列表模式查找器?
【发布时间】:2019-12-19 13:46:35
【问题描述】:

我正在尝试制作一个 python 列表模式查找器。我的第一个想法是获取列表中的第一个值,然后找到下一个相同值的出现。那将是潜在的模式序列长度,然后我将检查从第一个数字到第二个数字的数字是否等于潜在模式序列长度范围内的第二个数字之后的值。

例如:

如果我有这份清单

[1, 2, 6, 1, 2, 6, 1, 2, 6, 7, 8, 7, 8]

然后它将采用第一个数字1 并采用列表中第二个1 的索引减去第一个数字的索引。所以3 - 0 = 3,那就是模式长度。然后它会检查是否list[:3] == list[3:3 + pattern length]。依此类推,直到模式不匹配。最终结果将是[[3, [1, 2, 6]], [2, [7, 8]]]。最好有一个字典作为输出,但如果两个模式相同,字典将不起作用,因为它不能有两个相同的键。

我发现这种方法不是很有效,而且我的功能也没有完全成功,所以我想知道是否有人可以帮助我提供另一个模式查找器功能的想法,或者是否有一个 python 模块。

我在网上找到了这个:https://regex101.com/r/Vdhjld/1,这正是我想要的,但我的实际列表非常大,使用它需要很长时间。关于我应该做什么的任何想法?

如果描述不清楚,请评论

【问题讨论】:

  • 您描述的方法是错误的。例如:[1,2,1,3,1,2,1,3] 结果应该是[[2,[1,2,1,3]]] 对吧?而不是[[1,[1,2]],[1,[1,3]],[1,[1,2]],[1,[1,3]]]
  • 如果是[1, 2, 1, 2, 4, 5, 1, 2, 1, 2, 4, 5],你会期待什么?如果数字相同会发生什么?例如[1, 1, 1, 1] 是模式[1, [1], 1, [1],...] 还是[4, [1, 1, 1, 1]]
  • @Raj 抱歉,如果我解释不好,是的,结果应该是 [[2,[1,2,1,3]]],这就是我的方法很愚蠢的原因。
  • @DenFulaAnkungen 所以你不是在寻找最长的模式,而是最短的模式?
  • @LeoE 对不起,不。输出应该是[[2, [1, 2, 1, 2, 4, 5]]]。我会更新我的答案。对不起,我没有仔细查看列表。或者可能是[[2, [[2, [1, 2]], 4, 5]]

标签: python python-3.x list function dictionary


【解决方案1】:

我写这个是为了回答,因为它是为了详细的评论。
我认为您应该首先明确您的要求,这不是一个微不足道的问题,而且您的问题有多种解决方案,特别是如果它是一个很长的列表。

可能出现的问题的一些示例:

让我们先来看看以下列表:

[1, 2, 1, 2, 1, 2, 3, 1, 2, 1, 2, 3, 1, 2, 1]

在此列表中查找模式有多种(所有正确的)解决方案:

  1. [3, [1, 2], 1, [3], 2, [1, 2] , 1, [3, 1, 2, 1]
  2. [1, [1, 2], 2, [1, 2, 1, 2, 3], 1, [1, 2, 1]]
  3. [1, [1], 2, [2, 1], 2, [2, 3, 1, 2, 1]]
  4. [2, [1, 2], 2, [1, 2, 3, 1, 2], 1 [1]]

其中哪一项应该是您问题的“正确”答案?即使我们说,具有最长子序列的那个我们仍然有三个不同的解决方案。这只是列表长度为 15 并且只有三个不同的数字,列表越大,您的列表中可能会有更多不同的解决方案。我能想到的唯一解决方案是通过搜索最长的公共序列来任意选择一个解决方案,将其从列表中删除并重复此操作直到列表为空。但是,这可能会给您的排序带来问题,并且可能非常慢。如果有人有更好的方法,我很高兴听到。

它卡在我的脑海里,我无事可做,所以我只是试了一下,它没有排序,你必须这样做,但它提取了最长的常见模式。然而它是递归的,所以我不知道它是否适用于你的长列表,但它可能会让你知道如何解决它。我不认为这是迄今为止最快的方法,它只是处理它的一种方法。只需将其用作一个想法,并牢记这一点编写自己的代码。现在是(相当长的)代码:

test = [1, 2, 3, 1, 2, 3, 1, 2, 3, 4, 5, 4, 5, 1, 2, 3, 1, 2, 3, 1, 2, 3, 4, 5, 4]
test_1 = [1, 2, 3, 1, 2, 3, 1]
test_2 = [1, 2, 1, 2, 1, 2, 3, 1, 2, 1, 2, 3, 1, 2, 1, 2]
test_3 = [1, 1, 1, 2, 1, 1, 1]

def pattern_finder(mylist, pattern):
    matches = []
    i = 0
    while i < len(mylist):
        if mylist[i] == pattern[0] and mylist[i:i+len(pattern)] == pattern:
            matches.append(i)
            i += len(pattern)
        else:
            i+=1
    return matches

def get_patterns(list_input, p=None):
    if type(list_input[0]) != list:
        list_input = [list_input]
    result = []
    for list_in in list_input:
        if len(set(list_in)) == 1:
            result.append([1,list_in])
            continue
        n = len(list_in)
        if n == 1:
            result.append(list_in[0])
            continue
        p_len = p
        if p == None:
            p_len = int(n/2)
        lhs = 0
        rhs = lhs + p_len
        list_split = list_in
        if p_len <= 1:
            result.append([1, list_in])
            continue
        found = False
        while lhs < n - p_len and not found:
            rhs = lhs + p_len
            while rhs <= n-p_len:
                if list_in[lhs:lhs+p_len] == list_in[rhs:rhs+p_len]:
                    found = True
                    matches = pattern_finder(list_in, list_in[lhs:lhs+p_len])
                    list_split = []

                    for i,m in enumerate(matches):
                        if i == 0 and m != 0:
                            list_split.append(list_in[0:m])
                            continue
                        if i == len(matches)-1:
                            if m+p_len != n:
                                list_split.append(list_in[m+p_len:])
                            continue
                        if m+p_len != matches[i+1]:
                            list_split.append(list_in[m+p_len:matches[i+1]])
                    result.append([len(matches), list_in[lhs:lhs+p_len]])
                    break
                rhs += 1
            lhs += 1
        if list_split == []:
            continue
        if not found:
            result += get_patterns(list_split, p_len-1)
        else:
            result += get_patterns(list_split)
    return result

print("Result:", get_patterns(test))

【讨论】:

  • 非常感谢您为此付出了这么多时间,我真的很感激。我一定会看一下并尝试理解您代码中的所有内容。老实说,我不知道我是否会全部理解,但谢谢。我尝试在我的完整列表上运行它,它可能有效,但 20 分钟后它仍在运行。再次感谢
  • 最长的重复序列可以使用后缀树在 O(n) 中找到。 en.wikipedia.org/wiki/Longest_repeated_substring_problem
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-06-03
  • 2019-11-29
  • 1970-01-01
  • 1970-01-01
  • 2014-01-28
  • 2013-10-05
相关资源
最近更新 更多