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

时间:2016-10-12 19:03:22

标签: python python-3.x

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

  

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

     

当应用于example = [0,0,0,7,3,2,2,2,2,1]时,函数应该返回[(0,3),(5,9)],因为这两个例子[ 0:3]和示例[5:9]包含相同值的重复序列。

     

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

我知道我可以编写一堆循环来获得我想要的东西,但这似乎效率低下,我想知道是否有更容易的选择来获得我想要的东西。

3 个答案:

答案 0 :(得分:2)

使用itertools.groupbyenumerate

>>> 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的元素进行分组,以及将遍历该组的新的lazy-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>)]

答案 1 :(得分: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))。我觉得很容易理解,但如果你有任何疑问,请问。

答案 2 :(得分:0)

你可以用它。请注意,您的问题对于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)]