停止列表选择? [复制]
Posted
技术标签:
【中文标题】停止列表选择? [复制]【英文标题】:Stopping list selection? [duplicate] 【发布时间】:2015-09-09 07:03:06 【问题描述】:假设我有一个元组的顺序列表:
s = [(0,-1), (1,0), (2,-1), (3,0), (4,0), (5,-1), (6,0), (7,-1)]
给定一个参数X
,我想选择第一个元素等于或大于X
的所有元组,但不包括第一个元组的第二个元素为-1。
比如X = 3
,我想选择列表[(3,0), (4,0)]
我的一个想法是: 用
获取截止键E = min (x [0] for x in s if (x [0] >= X) and (x [1] == -1) )
然后用X
和E
之间的键选择元素:
R = [x for x in s if X <= x [0] < E]
这给了我在 R 中想要的东西,但它似乎真的效率低下,涉及两个表扫描。我可以在 for 循环中执行此操作,丢弃键太小的元组,并在遇到第一个阻塞元组时 break。但是与列表选择相比,像狗一样奔跑。
有没有一种超级高效的python-esque (2.7) 方式来做到这一点?
【问题讨论】:
【参考方案1】:在生成器表达式中实现takewhile
有点麻烦:
def stop(): raise StopIteration
result = (
stop() if item[1] == -1 else
item
for item in s
if item[0] >= X
)
或者用不同的措辞:
def until(cond):
if cond: raise StopIteration
return True
result = (
item for item in s
if item[0] >= X
and until(item[1] == -1)
)
【讨论】:
有趣的是,类似的方法在列表推导中不起作用,因为if
子句在推导/生成器内部代码处理的StopIteration
之外,因此异常传播。 (使用生成器也是如此,但它由使用生成器的代码自然地处理)。此评论是为了那些试图将这种技术应用于理解并感到惊讶的人的潜在利益,就像我一样。 :)【参考方案2】:
您可以简单地将列表中的元组过滤为生成器表达式,然后当您获得第二个元素为-1
的第一个元组时,您可以停止从生成器表达式中获取值,就像这样
>>> s = [(0,-1), (1,0), (2,-1), (3,0), (4,0), (5,-1), (6,0), (7,-1)]
>>> from itertools import takewhile
>>> X = 3
>>> list(takewhile(lambda x: x[1] != -1, (item for item in s if item[0] >= X)))
[(3, 0), (4, 0)]
这里,生成器表达式(item for item in s if item[0] >= X)
将根据需要一个接一个地给出值(它们不是一次全部生成的,所以我们在这里节省内存)大于或等于X
。
然后,我们从该生成器表达式中获取值,直到我们找到第二个元素不等于 -1
的元组与 itertools.takewhile
。
【讨论】:
您的回答优雅地满足了我的所有担忧。我喜极而泣。以上是关于停止列表选择? [复制]的主要内容,如果未能解决你的问题,请参考以下文章