使用itertools.dropwhile时遇到困难

时间:2012-08-22 21:45:22

标签: python itertools

我正在尝试使用itertools.dropwhile仅返回第三个元素之后的生成器中的元素,但是我遇到了一些麻烦:

from itertools import dropwhile

    it = (i for i in range(10,20))
    a = dropwhile(enumerate < 3, it)   
    next(a)
    TypeError: 'bool' object is not callable 

我正在寻找的输出是:

[14, 15, 16, 17, 18, 19]

有人能解释我的代码有什么问题并提供有效的解决方案吗?感谢。

5 个答案:

答案 0 :(得分:8)

itertools提供的功能可以完全满足您的需求。来自the Python Standard Library

  

itertools。 islice iterable [, start ], stop [,步骤])

     

创建一个从迭代中返回所选元素的迭代器。如果 start 非零,则跳过iterable中的元素,直到达到 start 。之后,除非将步骤设置为大于导致跳过项目的步骤,否则将连续返回元素。如果 stop None,则迭代继续,直到迭代器耗尽,如果有的话;否则,它会停在指定的位置。

>>> import itertools
>>> it = (i for i in range(10, 20)) # it = xrange(10, 20)
>>> a = itertools.islice(it, 4, None)
>>> list(a)
[14, 15, 16, 17, 18, 19]

答案 1 :(得分:3)

predicate的{​​{1}}参数应该是一个接受单个参数的函数,itertools.dropwhile只是一个语句。在Python 2.x上,这将始终评估为False,因为enumerate < 3,而在Python 3.x上,它将导致"type" > "int"

以下是您可以更改代码的方法,并仍使用TypeError: unorderable types: type() < int()

dropwhile

请注意,必须在iterable上调用>>> it = (i for i in range(10, 20)) >>> a = dropwhile(lambda i_v: i_v[0] < 4, enumerate(it)) >>> list(a) [(4, 14), (5, 15), (6, 16), (7, 17), (8, 18), (9, 19)] ,以便我们可以创建一个使用索引来确定是否删除当前值的lambda,但这意味着结果是{{ 1}}元组而不仅仅是值。我还将比较更改为enumerate,因为您希望从(index, value)开始,这是< 4的第四个元素。

更好的选择是在Deokhwan's answer中使用14

答案 2 :(得分:1)

此处的其他一些答案很有帮助,但他们并未准确提供所要求的结果。接受的答案解释了有用的itertools.islice(),但如果使用itertools.dropwhile()是必需的,那么它就不太对了。其他一些答案也不必要地复杂。

一个简单的解决方案可能比预期更容易找到。例如:

list(dropwhile(lambda x: x < 14, xrange(10, 20)))

我将其包含在list()中,因为请求的具体结果是[14, 15, 16, 17, 18, 19]。可以删除该部分以使用dropwhile()作为具有.next()等的迭代器。因为这是一个迭代器,而不是range()我使用了xrange(),因为它是&#39;使用迭代器更有效率。 range()可行,但可能效率不高。

我不确定目标的一部分是否也使用enumerate()。也许是,但在示例中enumerate被用作变量,而不是函数。获取所请求的结果并不是必需的,并且它不是问题的一部分,所以我认为它被错误地使用了。

正如其他人所指出的那样,问题中的例子并不需要使用理解来获得范围内的所有项目。这个答案也没有使用它。如果我们要进一步简化代码,获得所请求结果的最简单的解决方案是:

range(14, 20)

但这并不包括使用itertools.dropwhile()的目标。

答案 3 :(得分:-1)

试试:

a = dropwhile(lambda x:x < 3, it)  

参数必须是可调用的。

答案 4 :(得分:-1)

 it = (i for i in range(10,20))

这有点多余,为什么不简单地使用range(10,20)(或xrange)?

您的代码中断是因为dropwhile期望函数作为其参数,并且您提供了一个布尔值(通过比较函数enumerate与数字3进行比较,这有点奇怪!)

使用枚举的解决方案可能如下所示:

a = dropwhile(lambda (i,val): i<3), enumerate(seq))

但是a仍然是枚举对的列表(索引,值)。

更有效的方式可能看起来像这样:

class Counter:
    def __init__(self):
        self.n = 0

    def __call__(self):
        current = self.n
        self.n += 1
        return current

(见行动here,这很简单)

然后你就可以使用它:

c = Counter()
a = dropwhile(lambda elem: c() < 3, seq)

可让您使用dropwhile实现目标。对seq中的每个元素调用一次计数器实例,每次都给出下一个数字。


那就是说,使用itertools.islice

会好得多
import itertools
a = itertools.islice(range(10, 20), 3, None)

islice允许你像列表切片一样进行切片(在这种情况下,如myList[3:],从元素#3到结尾),但可以采用任何序列作为其参数。