如何制作一个过滤列表的迭代器?

时间:2018-08-16 15:31:41

标签: python iterator generator

我有一个过滤列表的生成器功能:

def gen_func(numbers):
    for number in numbers:
        if "?" in number:
            yield number

for item in gen_func(["trunk", "tr?ee", "+lea?f"]):
    print(item)

输出:

tr?ee
lea?f

我尝试编写一个迭代器,期望获得相同的输出,但是我得到的None作为第一项返回:

class GenClass:

    def __init__(self, numbers):
        self.current = 0
        self.numbers = numbers

    def __iter__(self):
        return self

    def __next__(self):
        next_value = self.current   

        if next_value >= len(self.numbers):
            raise StopIteration
        output = self.numbers[self.current]
        self.current += 1

        if "?" in output:
            return output

genclass = GenClass(["trunk", "tr?ee", "+lea?f"])
for num in genclass:
    print(num)

输出:

None
tr?ee
lea?f

如何仅获取tr?eelea?f而不是上面的内容? 另外,这个迭代器有意义吗?还是我在这里滥用了迭代器?

4 个答案:

答案 0 :(得分:1)

您需要将__next__的代码更改为:

        next_value = self.current

        if next_value >= len(self.numbers):
            raise StopIteration

        output = self.numbers[self.current]
        while "?" not in output:
            self.current += 1
            output = self.numbers[self.current]

        self.current += 1
        return output

这将返回:

tr?ee
+lea?f

本质上,您遍历数字,并且仅在数字包含?时返回。

答案 1 :(得分:1)

您可以使用 yield 代替 return 并仅使用__iter__。

class GenClass:
    def __init__(self, numbers):
        self.numbers = numbers

    def __iter__(self):
        for value  in self.numbers:
            if '?' in value:
                yield value


genclass = GenClass(["trunk", "tr?ee", "+lea?f"])
for num in genclass:
    print(num)

Out:
tr?ee
+lea?f

我上面的解决方案不是 iterator ,而是 iterable ,谢谢juanpa.arrivillaga。我认为最好将 iterable iterator 分开,在这种情况下,您可以分别实现GenClass和 iterator 。因此,如果您要遍历GenClass实例一次,则可以重复它而无需重置计数器(Daniel Mesejo解决方案中的GenClassIterator)。

class GenClass:
    def __init__(self, numbers):
        self.numbers = numbers

    def __iter__(self):
        return GenClassIterator(self.numbers)


class GenClassIterator:
    def __init__(self, numbers):
        self.numbers = numbers
        self.current = 0

    def __next__(self):
        next_value = self.current

        if next_value >= len(self.numbers):
            raise StopIteration

        output = self.numbers[self.current]
        while "?" not in output:
            self.current += 1
            output = self.numbers[self.current]

        self.current += 1
        return output

    def __iter__(self):
        return self

答案 2 :(得分:0)

numbers弹出项目,直到符合条件的项目,然后将其退回。

import collections
class GenClass:

    def __init__(self, numbers):
        self.numbers = collections.deque(numbers)

    def __iter__(self):
        return self

    def __next__(self):
        while True:
            try:
                next_value = self.numbers.popleft()
            except IndexError as e:
                raise StopIteration

            if "?" in next_value:
                return next_value

答案 3 :(得分:0)

您可以调用next(self)返回所需的值而无需返回None

class GenClass:

def __init__(self, numbers):
    self.current = 0
    self.numbers = numbers

def __iter__(self):
    return self

def __next__(self):
    next_value = self.current   

    if next_value >= len(self.numbers):
        raise StopIteration
    output = self.numbers[self.current]
    self.current += 1

    if "?" in output:
        return output
    else:
        return next(self)  # Skip value


genclass = GenClass(["trunk", "tr?ee", "+lea?f"])
for num in genclass:
     print(num)

这是更新的版本,在迭代过程中不会存储所有值

class GenClass:

def __init__(self, numbers):
    self.numbers = iter(numbers)

def __iter__(self):
    return self

def __next__(self):
    output = next(self.numbers)
    if "?" in output:
        return output
    else:
        return next(self)