从列表python的末尾删除连续出现的事件

时间:2014-05-01 00:11:42

标签: python list python-2.7 numpy

我有一个numpy数组:

ar = np.array([True, False, True, True, True])

如果最后一个元素为True,我想删除数组末尾的所有连续true元素。例如,

magic_func(ar) => [True, False]

如果ar = [True, False, True, False, True]。然后

magic_func(ar) => [True, False, True, False]

如果ar = [True, False, False],则该函数不执行任何操作,因为最后一个元素为False

python中是否有一个内衬来执行此操作?使用numpy库或其他东西

6 个答案:

答案 0 :(得分:1)

这一行函数应该可以工作,但看起来很讨厌,可能效率不高哈哈。基本上,我们的目标是找到最合适的False并在False

之前返回所有值
def magic_func(a):
    return a[:len(a)-np.where(a[::-1]==False)[0][0]] if np.where(a[::-1]==False)[0].size>0 else a[:0]

>>> a = np.array([False, True, True, True, True])
>>> magic_func(a)
array([False], dtype=bool)

答案 1 :(得分:1)

这对我来说有点太神奇了,但它似乎确实很有效:

>>> ar = np.array([True, False, True, True, True])
>>> ar[np.bitwise_or.accumulate(~ar[::-1])[::-1]]
array([ True, False], dtype=bool)

要理解发生了什么,首先我们否定数组,将True转换为False s而反之,然后我们反转顺序,然后我们累积OR的结果-ing数组:这将是False直到第一个True,之后将保持True。反转这个数组,我们有一个布尔索引数组,可以摆脱所有尾随的True

答案 2 :(得分:1)

像这样使用itertools.dropwhilenp.fromiter

from itertools import dropwhile
np.fromiter(dropwhile(lambda x: x, ar[::-1]), dtype=bool)[::-1]

修改

这是更快的方法。(只需使用itertools.takewhile

from itertools import takewhile
ar[:-sum(1 for i in takewhile(lambda x: x, reversed(ar)))]

时间:

ar = np.array([True, False, True, True, True])

#mine
%timeit ar[:-sum(1 for i in takewhile(lambda x: x, reversed(ar)))]
1000000 loops, best of 3: 1.84 us per loop

#mine
%timeit np.fromiter(dropwhile(lambda x: x, ar[::-1]), dtype=bool)[::-1]
100000 loops, best of 3: 2.93 us per loop

#@Jaime
%timeit ar[np.bitwise_or.accumulate(~ar[::-1])[::-1]]
100000 loops, best of 3: 3.63 us per loop

#@askewchan
%timeit ar[:len(ar)-np.argmin(ar[::-1])]
100000 loops, best of 3: 6.24 us per loop

#@xbb
%timeit ar[:len(ar)-np.where(ar[::-1]==False)[0][0]] if np.where(ar[::-1]==False)[0].size>0 else ar[:0]
100000 loops, best of 3: 7.61 us per loop

PS:

这是无魔法的功能。

def no_magic_func(ar):
    for i in xrange(ar.size-1, -1, -1):
        if not ar[i]:
            return ar[:i+1]
    return ar[0:0]

时间:

ar = np.array([True, False, True, True, True])

%timeit no_magic_func(ar)
1000000 loops, best of 3: 954 ns per loop

答案 3 :(得分:1)

编写一个节省时间的单行代码并不容易,但这里的代码基于askewchan删除的答案:

argmin = ar[::-1].argmin()
result = np.array([], dtype=bool) if ar[argmin] else ar[:len(ar)-argmin]

对于ar = np.full(1000000, True, dtype=bool)来说,比Jaime的基于Numpy的解决方案快两倍,然后是:

  • ar[-10] = False
  • ar[10] = False

(这是代表最佳和最差情况的两种情况)。但是,就像在Jaime的解决方案中一样,查找最后False使NumPy(1.8.1)的位置通过整个数组,这是低效的。但是,原则上,Numpy不必对argmin()执行此操作,因为它可能会在遇到的第一个False处停止。

这对我来说就像使用最好的Numpy 来执行执行剪切给出最终数组的解决方案。原则上,NumPy也可以非常有效地找到切割位置。

答案 4 :(得分:0)

编辑:更新实现以处理numpy数组中缺少.pop()

def chop_array(ar, condition):
    i = len(ar)
    while (ar[i - 1] == condition and i > 0):
        i = i - 1
    return ar[0:i]

chop_array([True, False, True, False, True], True)

答案 5 :(得分:0)

这里几乎是一行(对于结果不为空的情况,一行),这应该非常快(只查看必要的元素):

def magic_func(arr):
    try:       
        # The first element starting from the end which differs from the last one sets the limit:
        return arr[:next(index for index in xrange(len(arr)-1, -1, -1) if arr[index] == False)+1]
    except StopIteration:
        return numpy.empty_like(arr)

next()只返回第一个元素False的索引。最后的+1用于将其包含在结果中。 StopIteration适用于所有元素均为True的情况。

一个真正的单行稍微慢一些(对索引进行额外测试,产生的是所有元素而不是False):

ar[:next(index for index in xrange(len(ar)-1, -2, -1) if index == -1 or ar[index] == False)+1]

它相对清晰:从最后到开头扫描潜在最后一个元素的索引,如果没有找到False或者找到一个False,我们就会停止。

请注意,此解决方案的缺点是在不使用Numpy的情况下循环遍历原始数组(如果数组末尾有很多True值,则这不好)。它比许多其他解决方案有一些优势:

  • 扫描的唯一元素是必要的元素(无需在找到第一个False之前查看) - 但是,再次使用较慢的(非Numpy) )方法。
  • 结果是通过 Numpy切片获得的,

因此,当数组末尾的True值数量很少时,此解决方案非常快