我可以比较一下李斯特的一部分吗?

2024-03-29 05:52:41 发布

您现在位置:Python中文网/ 问答频道 /正文

此代码将选择列表“a”中的6个或更多正值

a=np.array([1.01, -1.58, 0.64, 1.38, 0.69, 0.91, 1.34, 1.03, 1.39, 0.94, -1.01,0.16])
b= np.zeros(13)
for i in range(6):
    if (a[i] > 0 and a[i+1] > 0 and a[i+2] > 0 and a[i+3] > 0\
        and a[i+4] > 0 and a[i+5] > 0 and a[i+6] > 0) :
            
            b[i] = a[i]
            b[i+1] = a[i+1]
            b[i+2] = a[i+2]
            b[i+3] = a[i+3]
            b[i+4] = a[i+4]
            b[i+5] = a[i+5]
            b[i+6] = a[i+6]

我想把它缩短,我试过:

for i in range (6):
    if (a[i:i+6]) > 0:
        b[i:i+6] = a[i:i+6]

Tags: and代码in列表forifnpzeros
2条回答

在缩短的版本中,您需要更改的主要内容是if (a[i:i+6]) > 0:。而且a的长度是12,b的长度是13。编辑1:(根据@Steve's comment below)此外,索引range循环也可以从for i in range(6)推广到for i in range(len(a)-5),因此:

b = np.zeros(len(a))
# b is 
# array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.])
for i in range(len(a)-5):
    if all(a[i:i+6] > 0):
        b[i:i+6] = a[i:i+6]

b
# output:
# array([0.  , 0.  , 0.64, 1.38, 0.69, 0.91, 1.34, 1.03, 1.39, 0.94, 0.  , 0.  ])

编辑2,根据@hpaulj's comment,因为a是一个numpy数组,我们不需要迭代切片,因为numpy将对数组(切片)的每个元素应用>操作符,并返回一个[True, False, ...]数组。第一个循环看起来是这样的:

例如a[0:0+6] > 0返回array([ True, False, True, True, True, True])


一次只检查6个元素的一个显著缺点是,如果是一个较长的连续正数组,则将在下一个循环中填充它,并在b中过度写入相同的值。所以不是很优化。最好对索引进行显式检查,直到得到非正(或结束),并确保当前计数为>;6.

重温这一点-我想我会添加这个替代方法,其中包括我在previous answer中提到的优化:

这个版本要长得多,需要手工编码每个正数序列的索引跟踪。但它有以下提到的主要性能优势

a = np.array([1.01, -1.58, 0.64, 1.38, 0.69, 0.91, 1.34, 1.03, 1.39, 0.94, -1.01, 0.16,])
b = np.zeros(len(a))

MIN_CONSECUTIVE = 6  # number of consecutive numbers wanted
first, last, c = -1, -1, 0  # index of first & last positive number, count of +ve nums
nums = []  # hold each series of consecutive positive numbers

for i, n in enumerate(a):
    if n > 0:
        nums.append(n)
        first = i if first == -1 else first
        last = i
        c += 1
    else:
        if c >= MIN_CONSECUTIVE:
            b[first:last+1] = nums
        first, last, c = -1, -1, 0  # reset
        nums = []  # reset
        if i > len(a) - MIN_CONSECUTIVE - 1:  # shortcut exit if there aren't
            break                             # enough elems left for consecutive

else:  # if the loop completes without `break`
    if c >= MIN_CONSECUTIVE:  # also check after the loop completes
        b[first:last+1] = nums

b  # -> array([0.  , 0.  , 0.64, 1.38, 0.69, 0.91, 1.34, 1.03, 1.39, 0.94, 0.  , 0.  ])

为什么这样更好:

  1. 这个函数只访问numpy数组(或python列表)中的每个项目一次。
    • 您尝试的方法,以及在注释和我之前的回答中提供的方法,在数组中多次查找重叠的元素序列
    • 前一个也会多次重新写入b,并使用相同的值进行重复写入
  2. 这只会在找到并完成每个系列后写入b
  3. 我用^{}跟踪索引,但我不使用索引访问元素。python列表上的索引访问比只遍历列表元素要慢The same is true for numpy arrays.
  4. 对于给定的列表,此列表的运行时间不到上一个答案的一半:
    • 该值:14.6µs±584 ns
    • 上一个:31.9µs±1.13µs

相关问题 更多 >