python – 匹配列表中的元素,然后在它之前返回`n`元素,在它之后返回`m`元素

我的代码中的一个常见模式是:“搜索列表直到找到特定元素,然后查看它之前和之后的元素.”

作为一个例子,我可能想查看一个日志文件,其中重要事件用星号标记,然后拉出重要事件的上下文.

在下面的例子中,我想知道为什么超级驱动器爆炸了:

  Spinning up the hyperdrive
  Hyperdrive speed 100 rpm
  Hyperdrive speed 200 rpm
  Hyperdrive lubricant levels low (100 gal.)
* CRITICAL EXISTENCE FAILURE
  Hyperdrive exploded

我想要一个函数get_item_with_context(),它允许我找到带星号的第一行,然后在它之前给我最多n行,并在它后面有m行.

我的尝试如下:

import collections, itertools
def get_item_with_context(predicate, iterable, items_before = 0, items_after = 0):
    # Searches through the list of `items` until an item matching `predicate` is found.
    # Then return that item.
    # If no item matching predicate is found, return None.
    # Optionally, also return up to `items_before` items preceding the target, and
    # `items after` items after the target.
    #
    # Note:
    d = collections.deque (maxlen = items_before + 1 + items_after)
    iter1 = iterable.__iter__()
    iter2 = itertools.takewhile(lambda x: not(predicate(x)), iter1)    
    d.extend(iter2)

    # zero-length input, or no matching item
    if len(d) == 0 or not(predicate(d[-1])):
        return None

    # get context after match:
    try:
        for i in xrange(items_after):
            d.append(iter1.next())
    except StopIteration:
        pass

    if ( items_before == 0 and items_after == 0):
        return d[0]
    else:
        return list(d)

用法应该是:

>>> get_item_with_context(lambda x: x == 3, [1,2,3,4,5,6],
                          items_before = 1, items_after = 1)
[2, 3, 4]

这个问题:

>检查以确保我们实际找到匹配,使用not(谓词(d [-1])),由于某种原因不起作用.它总是返回false.
>如果找到匹配项后列表中的items_after项少于,则结果为垃圾.
>其他边缘情况?

我可以就如何使这项工作变得更加健壮吗?或者,如果我重新发明*,请随时告诉我.

解决方法:

这似乎正确处理边缘情况:

from collections import deque

def item_with_context(predicate, seq, before=0, after=0):
    q = deque(maxlen=before)
    it = iter(seq)

    for s in it:
        if predicate(s):
            return list(q) + [s] + [x for _,x in zip(range(after), it)]
        q.append(s)
上一篇:迭代器切片操作


下一篇:合并itertools.product的结果?