python - 重复可迭代对象元素的迭代器
python - Iterator which duplicates elements of iterable object
我需要编写一个函数 duplicate(it)
,其中 returns 迭代器复制可迭代 it
的元素。示例:如果 it = [1, 2, 3]
则 list(duplicate(it)) == [1, 1, 2, 2, 3, 3]
。我尝试为列表实现 DoubleIterator
class 和 duplicate(it)
函数(不确定在这种情况下 DoubleIterator
的正确实现方式,欢迎提供有用的建议):
class DoubleIterator():
def __init__(self, data):
self.data = data
self.pos = 0
self.limit = len(data)
self.dup = 0
def next(self): # __next__ for Python 3
if self.dup != 0 and self.dup % 2 == 0:
self.pos = self.pos + 1
if self.pos < self.limit:
self.dup += 1
return self.data[self.pos]
else:
raise StopIteration
def __iter__(self):
return self
def duplicate(it):
itr = DoubleIterator(it)
return iter(itr)
它适用于 list(duplicate(it)) == [1, 1, 2, 2, 3, 3]
示例和类似的东西:
dup = duplicate([1, 2, 3])
print next(dup) #1
print next(dup) #1
print next(dup) #2
print next(dup) #2
print next(dup) #3
print next(dup) #3
但是此功能的任务测试之一是 dup = duplicate(iter([1, 2, 3]))
,它给出了一个错误:TypeError: object of type 'listiterator' has no len()
。我应该如何以正确的方式实现 duplicate
函数和迭代器 class?
我会做一个发电机
def duplicate(it,n=2):
for x in it:
for _ in range(n):
yield x
你把事情复杂化了一点。您需要做的就是获取下一个元素并 yield 两次。您确实需要将输入视为迭代器,而不是序列。只有像列表这样的序列才有长度并且可以被索引,迭代器所能做的就是给你下一个值直到它耗尽。
对于 class-based 迭代器,这意味着您需要存储要重复的元素,以便对 next()
的每个其他调用都可以生成该存储的值,而其他调用则获取下一个元素来自输入迭代器:
class DoubleIterator:
_sentinel = object()
def __init__(self, iterator):
self._data = iter(iterator)
self._repeat = self._sentinel
def next(self): # __next__ for Python 3
if self._repeat is self._sentinel:
# get next element to yield, can raise StopIteration
self._repeat = next(self._data)
return self._repeat
# repeat last element
element = self._repeat
self._repeat = self._sentinel
return element
def __iter__(self):
return self
我使用了一个独特的哨兵来确保支持输入迭代器中的 None
值,并且我在输入迭代器上调用了 iter()
以确保我们始终可以调用 next()
在那个对象上。
但是,更容易在这里只写一个生成器函数,并产生每个元素两次:
def double_iterator(iterator):
for elem in iterator:
yield elem
yield elem
你可以用循环进一步推广,但如果你只需要将元素加倍,我会坚持使用更简单的双 yield
.
我需要编写一个函数 duplicate(it)
,其中 returns 迭代器复制可迭代 it
的元素。示例:如果 it = [1, 2, 3]
则 list(duplicate(it)) == [1, 1, 2, 2, 3, 3]
。我尝试为列表实现 DoubleIterator
class 和 duplicate(it)
函数(不确定在这种情况下 DoubleIterator
的正确实现方式,欢迎提供有用的建议):
class DoubleIterator():
def __init__(self, data):
self.data = data
self.pos = 0
self.limit = len(data)
self.dup = 0
def next(self): # __next__ for Python 3
if self.dup != 0 and self.dup % 2 == 0:
self.pos = self.pos + 1
if self.pos < self.limit:
self.dup += 1
return self.data[self.pos]
else:
raise StopIteration
def __iter__(self):
return self
def duplicate(it):
itr = DoubleIterator(it)
return iter(itr)
它适用于 list(duplicate(it)) == [1, 1, 2, 2, 3, 3]
示例和类似的东西:
dup = duplicate([1, 2, 3])
print next(dup) #1
print next(dup) #1
print next(dup) #2
print next(dup) #2
print next(dup) #3
print next(dup) #3
但是此功能的任务测试之一是 dup = duplicate(iter([1, 2, 3]))
,它给出了一个错误:TypeError: object of type 'listiterator' has no len()
。我应该如何以正确的方式实现 duplicate
函数和迭代器 class?
我会做一个发电机
def duplicate(it,n=2):
for x in it:
for _ in range(n):
yield x
你把事情复杂化了一点。您需要做的就是获取下一个元素并 yield 两次。您确实需要将输入视为迭代器,而不是序列。只有像列表这样的序列才有长度并且可以被索引,迭代器所能做的就是给你下一个值直到它耗尽。
对于 class-based 迭代器,这意味着您需要存储要重复的元素,以便对 next()
的每个其他调用都可以生成该存储的值,而其他调用则获取下一个元素来自输入迭代器:
class DoubleIterator:
_sentinel = object()
def __init__(self, iterator):
self._data = iter(iterator)
self._repeat = self._sentinel
def next(self): # __next__ for Python 3
if self._repeat is self._sentinel:
# get next element to yield, can raise StopIteration
self._repeat = next(self._data)
return self._repeat
# repeat last element
element = self._repeat
self._repeat = self._sentinel
return element
def __iter__(self):
return self
我使用了一个独特的哨兵来确保支持输入迭代器中的 None
值,并且我在输入迭代器上调用了 iter()
以确保我们始终可以调用 next()
在那个对象上。
但是,更容易在这里只写一个生成器函数,并产生每个元素两次:
def double_iterator(iterator):
for elem in iterator:
yield elem
yield elem
你可以用循环进一步推广,但如果你只需要将元素加倍,我会坚持使用更简单的双 yield
.