【问题标题】:Could I compare part of liste?我可以比较列表的一部分吗?
【发布时间】:2020-11-26 15:39:27
【问题描述】:

此代码将选择列表“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]

【问题讨论】:

  • @Steve 很抱歉覆盖了编辑,我认为 # 标志是 cmets,还有一些拼写错误需要修复
  • 你的代码应该做什么
  • 它应该从数组 'a' 中取 6 或更多 + valeus,并像第一部分一样将其存储在 'b' 中
  • @YoussefGC - 编辑没问题
  • 我不明白为什么这个问题这么快就结束了。我对 OP 有一些问题,但我了解他们基本上想要做什么。我认为 SO 社区通常对问题的结束感到非常高兴。

标签: python arrays list numpy


【解决方案1】:

重新审视这个 - 我想添加这种替代方法,其中包括我在 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 列表)中的每个项目恰好一次。
    • 您尝试并在 cmets 和我之前的回答中提供的方法多次查找 重叠 数组中的一系列元素
    • 前一个也多次重写到b,并用相同的值覆盖
  2. 只有在找到并完成每个系列后才会写入 b。
  3. 我正在使用 enumerate() 跟踪索引,但我不使用索引来访问元素。 python 列表上的索引访问比仅遍历列表的元素要慢。 The same is true for numpy arrays.
  4. 对于您给定的列表,此列表的运行时间不到上一个答案的一半:
    • 这:14.6 µs ± 584 ns
    • 上一页:31.9 µs ± 1.13 µs

【讨论】:

    【解决方案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)So:

    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。

    【讨论】:

    • 不错的答案。我认为for i in range(6): 应该根据输入列表的长度进行概括。 = for i in range(len(a)-5):
    • 好收获。因为我概括了b 的长度。编辑。
    • 我还强烈要求/建议您不要发布 REPL 代码运行。它们阻止其他人快速复制/粘贴您的代码以尝试或使用它。 - 它们通常也不太可读
    • 我们中的许多人发布ipython REPL 代码。可以将其复制粘贴回ipython 会话(至少是IN 部分)。此答案的原始 for 循环部分也适用于 ipython 会话。但我经常发布无标题版本的函数。
    • 如果a是一个数组,则不需要在测试中迭代。
    猜你喜欢
    • 2019-07-09
    • 2010-09-22
    • 2021-10-16
    • 1970-01-01
    • 2011-10-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多