扫描列表以查找5个连续的大于x的值。

10

我想要扫描一个大列表,查找连续的数值是否大于x。这里的例子x大于1.0。

例如,

my_list = [0.2, 0.1, 0.3, 1.1, 0.7, 0.5, 1.2, 1.3, 1.4, 1.2, 1.9, 1.1, 0.2, 1.3, 1.5, 1.4, 1.2, 1.1, 0.2, 1.3, 0.1., 1.6, 0.2, 0.5, 1.0, 1.1, 0.2]

我可以通过以下方式对这个列表进行子集操作:

for i in range(0, len(my_list)):
    subset = my_list[i:i+5]

那么我理解

[0.2, 0.1, 0.3, 1.1, 0.7]
[0.1, 0.3, 1.1, 0.7, 0.5]
[0.3, 1.1, 0.7, 0.5, 1.2]
[1.1, 0.7, 0.5, 1.2, 1.3]
[0.7, 0.5, 1.2, 1.3, 1.4]
[0.5, 1.2, 1.3, 1.4, 1.2]
[1.2, 1.3, 1.4, 1.2, 1.9] <-- values I want
[1.3, 1.4, 1.2, 1.9, 1.1] <-- values I want
[1.4, 1.2, 1.9, 1.1, 0.2]
[1.2, 1.9, 1.1, 0.2, 1.3]
[1.9, 1.1, 0.2, 1.3, 1.5]
[1.1, 0.2, 1.3, 1.5, 1.4]
[0.2, 1.3, 1.5, 1.4, 1.2]
[1.3, 1.5, 1.4, 1.2, 1.1] <-- values I want

最好的方法是什么?


列出所有的子集,然后测试每个子集以查看其是否符合您的标准。 - Barmar
5个回答

5

这里有一种基于 itertools 的方法,不需要任何额外的内存,并且返回结果作为生成器:

from itertools import tee, islice

def find_consecutive(the_list, threshold, count=5):
    my_iters = tee(the_list, count)
    for i, it in enumerate(my_iters):
        next(islice(it, i, i), None)
    return (f for f in zip(*my_iters) if all(x > threshold for x in f))

my_list = [0.2, 0.1, 0.3, 1.1, 0.7, 0.5, 1.2, 1.3, 1.4, 1.2, 1.9, 1.1, 0.2, 1.3, 1.5, 1.4, 1.2, 1.1, 0.2, 1.3, 0.1, 1.6, 0.2, 0.5, 1.0, 1.1, 0.2]
list(find_consecutive(my_list, 1.0))
# [(1.2, 1.3, 1.4, 1.2, 1.9),
# (1.3, 1.4, 1.2, 1.9, 1.1),
# (1.3, 1.5, 1.4, 1.2, 1.1)]

该函数由阈值和计数参数化,因此您可以查找任何N个连续值。您甚至可以通过传递一个函数而不仅仅是阈值来分解条件。


1
非常好的回答,稍微扩展一下,您如何生成子集的索引而不是实际值呢? - jcp
1
@osonuyi 你可以使用 return (i for i, f in enumerate(zip(*my_iters)) ... 来返回每个n-slice的起始索引。 - tzaman

3
您可以按照以下方式进行操作:
my_list = [0.2, 0.1, 0.3, 1.1, 0.7, 0.5, 1.2, 1.3, 1.4, 1.2, 1.9, 1.1, 0.2, 1.3, 1.5, 1.4, 1.2, 1.1, 0.2, 1.3, 0.1, 1.6, 0.2, 0.5, 1.0, 1.1, 0.2]

x = 1

result = [my_list[i:i+5] for i in range(len(my_list)-4) if all(i > x for i in my_list[i:i+5])]

1
>>>my_list = [0.2, 0.1, 0.3, 1.1, 0.7, 0.5, 1.2, 1.3, 1.4, 1.2, 1.9,
1.1, 0.2, 1.3, 1.5, 1.4, 1.2, 1.1, 0.2, 1.3, 0.1, 1.6, 0.2, 0.5, 1.0,1.1, 0.2]

>>>x = 1.0
>>>for i in range(0, len(my_list)):
       subset = my_list[i:i+5]
       if(all(item >x for item in subset)):
           print subset

[1.2, 1.3, 1.4, 1.2, 1.9]
[1.3, 1.4, 1.2, 1.9, 1.1]
[1.3, 1.5, 1.4, 1.2, 1.1]

这在列表末尾不会完全正常运行。如果最后5个元素大于1.0,则会得到 [n-4,n-3,n-2,n-1][n-3,n-2,n-1][n-2,n-1][n-1] - Uyghur Lives Matter

1

为了节省时间,可以使用计数器来避免重复检查已经检查过的值。这里n=5

def scan_k(arr, val,n):
    counter = 0
    results = set()
    for i in range(len(arr)):
        if arr[i] > val:
            counter +=1
        else:
            counter = 0
            continue
        if counter >= n:
            results.add(arr[(i-n+1):i])
return(results)

0
这是一个使用生成器函数和一个变量来追踪到目前为止遇到的数字的快速解决方案:
def find_n_consecutive_greater_than_x(mylist, n, x):
    num_greater_than_x = 0
    for index, val in enumerate(mylist):
        if val > x:
            num_greater_than_x += 1
            if num_greater_than_x == n:
                yield tuple(mylist[index-n+1:index+1])
                num_greater_than_x -= 1
        else:
            num_greater_than_x = 0

mylist = [2]*6
n = 5
x = 1.0

print(list(find_n_consecutive_greater_than_x(mylist, n, x)))
# [(2, 2, 2, 2, 2), (2, 2, 2, 2, 2)]

这将比计算给定列表的所有长度为5的切片的任何解决方案都要快得多,因为它只处理每个元素一次,并避免创建对象,这在大多数Python实现中非常缓慢。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接