Iterators: Difference between revisions

3,847 bytes added ,  1 year ago
A Python implementation
(A Python implementation)
Line 436:
Saturday Wednesday Tuesday
Purple Yellow Orange
</pre>
 
=={{header|Python}}==
Python's built-in containers (list, dict, collections.deque, etc.) are ''iterable''. When an iterable object is used in a <code>for</code> loop, a new ''iterator'' is created automatically. Alternatively, the built-in <code>iter()</code> function can be used to obtain an iterator for an iterable, allowing us to single step through it's members using <code>next()</code>. When an iterator has been exhausted, calls to <code>next()</code> will raise a <code>StopIteration</code> exception.
 
We can create our own iterators by implementing the ''iterator protocol''. The iterator protocol requires us to implement an <code>__iter__</code> method and a <code>__next__</code> method, as demonstrated by the <code>MyIterable</code> and <code>MyIterator</code> classes below.
 
<lang python>"""Iterables and iterators. Requires Python >= 3.6 for type hints."""
from collections import deque
from typing import Iterable
from typing import Iterator
from typing import Reversible
 
# array-like
days = [
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday",
"Sunday",
]
 
# deque is implemented as a doubly linked list
colors = deque(
[
"red",
"yellow",
"pink",
"green",
"purple",
"orange",
"blue",
]
)
 
 
class MyIterable:
class MyIterator:
def __init__(self) -> None:
self._day = -1
 
def __iter__(self):
return self
 
def __next__(self):
if self._day >= 6:
raise StopIteration
 
self._day += 1
return days[self._day]
 
class MyReversedIterator:
def __init__(self) -> None:
self._day = 7
 
def __iter__(self):
return self
 
def __next__(self):
if self._day <= 0:
raise StopIteration
 
self._day -= 1
return days[self._day]
 
def __iter__(self):
return self.MyIterator()
 
def __reversed__(self):
return self.MyReversedIterator()
 
 
def print_elements(container: Iterable[object]) -> None:
for element in container:
print(element, end=" ")
print("") # for trailing newline
 
 
def _drop(it: Iterator[object], n: int) -> None:
"""Helper function to advance the iterator at most `n` times."""
try:
for _ in range(n):
next(it)
except StopIteration:
pass
 
 
def print_first_fourth_fifth(container: Iterable[object]) -> None:
# Get an iterator from the iterable
it = iter(container)
print(next(it), end=" ")
_drop(it, 2)
print(next(it), end=" ")
print(next(it))
 
 
def print_reversed_first_fourth_fifth(container: Reversible[object]) -> None:
# Reverse iterator
it = reversed(container)
print(next(it), end=" ")
_drop(it, 2)
print(next(it), end=" ")
print(next(it))
 
 
def main() -> None:
my_iterable = MyIterable()
 
print("All elements:")
print_elements(days)
print_elements(colors)
print_elements(my_iterable)
 
print("\nFirst, fourth, fifth:")
print_first_fourth_fifth(days)
print_first_fourth_fifth(colors)
print_first_fourth_fifth(my_iterable)
 
print("\nLast, fourth to last, fifth to last:")
print_reversed_first_fourth_fifth(days)
print_reversed_first_fourth_fifth(colors)
print_reversed_first_fourth_fifth(my_iterable)
 
 
if __name__ == "__main__":
main()
</lang>
 
{{out}}
<pre>
All elements:
Monday Tuesday Wednesday Thursday Friday Saturday Sunday
red yellow pink green purple orange blue
Monday Tuesday Wednesday Thursday Friday Saturday Sunday
 
First, fourth, fifth:
Monday Thursday Friday
red green purple
Monday Thursday Friday
 
Last, fourth to last, fifth to last:
Sunday Thursday Wednesday
blue green pink
Sunday Thursday Wednesday
</pre>
 
140

edits