summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRaymond Hettinger <python@rcn.com>2003-09-08 23:58:40 (GMT)
committerRaymond Hettinger <python@rcn.com>2003-09-08 23:58:40 (GMT)
commita098b33c9346ae8c8891982cd733d5d9dcdae2ec (patch)
tree0f79aae580e1af9335a3b0f9fc77d27db5bbb978
parent9d50d91e77974c233c1c136f1a7a8ce7d53cea09 (diff)
downloadcpython-a098b33c9346ae8c8891982cd733d5d9dcdae2ec.zip
cpython-a098b33c9346ae8c8891982cd733d5d9dcdae2ec.tar.gz
cpython-a098b33c9346ae8c8891982cd733d5d9dcdae2ec.tar.bz2
Add an example to address a common question of how to split iterators.
-rw-r--r--Doc/lib/libitertools.tex27
-rw-r--r--Lib/test/test_itertools.py34
2 files changed, 50 insertions, 11 deletions
diff --git a/Doc/lib/libitertools.tex b/Doc/lib/libitertools.tex
index 7fdd602..453d16e 100644
--- a/Doc/lib/libitertools.tex
+++ b/Doc/lib/libitertools.tex
@@ -321,13 +321,15 @@ Samuele
\end{verbatim}
-This section has further examples of how itertools can be combined.
-Note that \function{enumerate()} and \method{iteritems()} already
-have highly efficient implementations in Python. They are only
-included here to illustrate how higher level tools can be created
-from building blocks.
+This section shows how itertools can be combined to create other more
+powerful itertools. Note that \function{enumerate()} and \method{iteritems()}
+already have efficient implementations in Python. They are only included here
+to illustrate how higher level tools can be created from building blocks.
\begin{verbatim}
+def take(n, seq):
+ return list(islice(seq, n))
+
def enumerate(iterable):
return izip(count(), iterable)
@@ -380,7 +382,18 @@ def window(seq, n=2):
result = result[1:] + (elem,)
yield result
-def take(n, seq):
- return list(islice(seq, n))
+def tee(iterable):
+ "Return two independent iterators from a single iterable"
+ def gen(next, data={}, cnt=[0]):
+ dpop = data.pop
+ for i in count():
+ if i == cnt[0]:
+ item = data[i] = next()
+ cnt[0] += 1
+ else:
+ item = dpop(i)
+ yield item
+ next = iter(iterable).next
+ return (gen(next), gen(next))
\end{verbatim}
diff --git a/Lib/test/test_itertools.py b/Lib/test/test_itertools.py
index 057b576..8ab4cea 100644
--- a/Lib/test/test_itertools.py
+++ b/Lib/test/test_itertools.py
@@ -487,6 +487,9 @@ Martin
Walter
Samuele
+>>> def take(n, seq):
+... return list(islice(seq, n))
+
>>> def enumerate(iterable):
... return izip(count(), iterable)
@@ -539,12 +542,26 @@ Samuele
... result = result[1:] + (elem,)
... yield result
->>> def take(n, seq):
-... return list(islice(seq, n))
+>>> def tee(iterable):
+... "Return two independent iterators from a single iterable"
+... def gen(next, data={}, cnt=[0]):
+... dpop = data.pop
+... for i in count():
+... if i == cnt[0]:
+... item = data[i] = next()
+... cnt[0] += 1
+... else:
+... item = dpop(i)
+... yield item
+... next = iter(iterable).next
+... return (gen(next), gen(next))
This is not part of the examples but it tests to make sure the definitions
perform as purported.
+>>> take(10, count())
+[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
+
>>> list(enumerate('abc'))
[(0, 'a'), (1, 'b'), (2, 'c')]
@@ -590,8 +607,17 @@ False
>>> dotproduct([1,2,3], [4,5,6])
32
->>> take(10, count())
-[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
+>>> def irange(start, stop):
+... for i in range(start, stop):
+... yield i
+
+>>> x, y = tee(irange(2,10))
+>>> list(x), list(y)
+([2, 3, 4, 5, 6, 7, 8, 9], [2, 3, 4, 5, 6, 7, 8, 9])
+
+>>> x, y = tee(irange(2,10))
+>>> zip(x, y)
+[(2, 2), (3, 3), (4, 4), (5, 5), (6, 6), (7, 7), (8, 8), (9, 9)]
"""