Python 查找列表中重复序列索引的有效方法?

Python 查找列表中重复序列索引的有效方法?,python,python-3.x,Python,Python 3.x,我在python中有一个很大的数字列表,我想编写一个函数,用于查找列表中重复次数超过n次的部分。例如,如果n为3,则我的函数应为以下示例返回以下结果: 当应用于示例=[1,2,1,1,1,1,2,3]时,函数应返回[(2,6)],因为示例[2:6]是一个包含所有相同值的序列 应用于示例=[0,0,0,7,3,2,2,2,2,1]时,函数应返回[(0,3)、(5,9)],因为示例[0:3]和示例[5:9]都包含相同值的重复序列 当应用于示例=[1,2,1,2,1,2,1,2,1,2]时,该函数应返

我在python中有一个很大的数字列表,我想编写一个函数,用于查找列表中重复次数超过n次的部分。例如,如果n为3,则我的函数应为以下示例返回以下结果:

当应用于示例=[1,2,1,1,1,1,2,3]时,函数应返回[(2,6)],因为示例[2:6]是一个包含所有相同值的序列

应用于示例=[0,0,0,7,3,2,2,2,2,1]时,函数应返回[(0,3)、(5,9)],因为示例[0:3]和示例[5:9]都包含相同值的重复序列

当应用于示例=[1,2,1,2,1,2,1,2,1,2]时,该函数应返回[],因为没有三个或更多元素的序列都是相同的数字


我知道我可以编写一系列循环来获得我想要的东西,但这似乎有点低效,我想知道是否有更简单的方法来获得我想要的东西。

使用
itertools.groupby
enumerate

>>> from itertools import groupby
>>> n = 3
>>> x = [1,2,1,1,1,1,2,3] 
>>> grouped = (list(g) for _,g in groupby(enumerate(x), lambda t:t[1]))
>>> [(g[0][0], g[-1][0] + 1) for g in grouped if len(g) >= n]
[(2, 6)]
>>> x = [0,0,0,7,3,2,2,2,2,1]
>>> grouped = (list(g) for _,g in groupby(enumerate(x), lambda t:t[1]))
>>> [(g[0][0], g[-1][0] + 1) for g in grouped if len(g) >= n]
[(0, 3), (5, 9)]
要理解groupby:只需认识到每次迭代都会返回键的值,该键用于对iterable的元素进行分组,另外还有一个新的惰性iterable,它将在组中进行迭代

>>> list(groupby(enumerate(x), lambda t:t[1]))
[(0, <itertools._grouper object at 0x7fc90a707bd0>), (7, <itertools._grouper object at 0x7fc90a707ad0>), (3, <itertools._grouper object at 0x7fc90a707950>), (2, <itertools._grouper object at 0x7fc90a707c10>), (1, <itertools._grouper object at 0x7fc90a707c50>)]
列表(groupby(枚举(x),lambda t:t[1])) [(0, ), (7, ), (3, ), (2, ), (1, )]
您可以按照当前算法在单个循环中执行此操作:

def find_pairs (array, n):
    result_pairs = []
    prev = idx = 0
    count = 1
    for i in range (0, len(array)):
        if(i > 0):
            if(array[i] == prev):
                count += 1
            else:
                if(count >= n):
                    result_pairs.append((idx, i))
                else:
                    prev = array[i]
                    idx = i
                count = 1
        else:
            prev = array[i]
            idx = i
    return result_pairs

您可以这样调用函数:
find_pairs(list,n)
。这是执行此任务最有效的方法,因为它的复杂性为O(len(array))。我认为这很容易理解,但如果你有任何疑问,尽管问。

你可以用这个。请注意,您的问题对于n的角色是不明确的。这里我假设一系列n个相等的值应该匹配。如果至少有n+1个值,则用
替换
=

def monotoneRanges(a, n):
    idx = [i for i, v in enumerate(a) if not i or a[i-1] != v] + [len(a)]
    return [r for r in zip(idx, idx[1:]) if r[1] >= r[0]+n]

# example call
res = monotoneRanges([0,0,0,7,3,2,2,2,2,1], 3)

print(res)
产出:

[(0, 3), (5, 9)]

请提供您尝试过的代码。您真正想要找到的是列表中重复部分的切片参数,而不是索引。第二个例子要么是错误的,要么n的定义是错误的。开始时有3个零,因此零的重复次数不会超过n次。谢谢,这肯定比我之前做的要有效得多。我想知道这到底是怎么回事。我得到了enumerate(x)和key函数所做的,但是groupby究竟返回什么呢?为什么我们需要下半场而不是上半场?在调用该函数之后,我开始迷路了。如果您需要所有的组,可能效率最高,但如果您不同时需要所有的子序列,并且对它们的生成器感到满意,我想知道它是否会更慢。@FilipMalczak如果我理解正确,那么可以通过替换最后的列表理解来轻松实现另一个生成器表达式。是的,基本上,但是整个groupby(…)是在理解之前执行的。我想你可以将它包装在另一个用于理解的生成器中,甚至可以将其内联。我只是想知道,如果某个解决方案能够在找到每个子序列后立即生成它,它是否会更快一点。@FilipMalczak是的,这一定是对列表进行了两次遍历,但是如果你将其封装在生成器中,你可以从中挤出最后一点效率。这是一个很好的答案,呈现了“经典”命令式编程技术。话虽如此,您应该修复缩进。很好,但您需要处理一个边缘情况:
单调性([0,0,0,7,3,2,2,2,1,0],3)
@juanpa.arrivillaga,感谢您注意到这一点。我想我用添加的
而不是I
条件修复了它。