【发布时间】:2012-05-03 09:17:26
【问题描述】:
我的代码中的一个常见模式是:“搜索一个列表,直到找到一个特定元素,然后查看它之前和之后的元素。”
例如,我可能想查看一个日志文件,其中重要事件标有星号,然后提取重要事件的上下文。
在下面的例子中,我想知道为什么超光驱爆炸了:
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(predicate(d[-1]))检查以确保我们确实找到了匹配项,但由于某种原因无法正常工作。它总是返回 false。 - 如果找到匹配项后列表中的项少于
items_after,则结果为垃圾。 - 其他极端情况?
我能否就如何使这项工作/使其更强大提供一些建议?或者,如果我要重新发明轮子,也请随时告诉我。
【问题讨论】:
-
这是切片无法完成的事情吗?
-
@BurhanKhalid:我可能正在使用无法重绕的可迭代对象。
-
你为什么用
iterable.__iter__()而不是iter(iterable)? -
@jamylak:因为我很傻。 ;)
-
我不明白你的结果。不应该是
[2, 3, 4]吗?另外我想知道是否可以通过 grep 等工具轻松完成某些事情,是否有选择 Python 的理由(除了你的讽刺回答,我很傻 :-))