想象一下,我有一个元组的顺序列表:
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循环中执行它,丢弃键太小的元组,并且当我击中第一个阻塞元组时中断。但对于像狗一样的跑步与列表选择相比。
是否有超高效,python-esque(2.7)的方法呢?
答案 0 :(得分:28)
您可以简单地将列表中的元组作为生成器表达式进行过滤,然后当您获得第二个元素为-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)
将根据需要一个接一个地给出值(它们不是一次全部生成,因此我们在这里保存内存)大于或等于{{ 1}}。
然后,我们从该生成器表达式中获取值,直到找到第二个元素不等于X
的元组,并itertools.takewhile
。
答案 1 :(得分:1)
实现takewhile
作为生成器表达式的一部分时,有点hacky:
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)
)