Re: Exception Names
On Mon, 30 Mar 2009, Eric Sosman wrote:
Tom Anderson wrote:
Is this a good time to mention that in python, iterators don't have a
hasNext method, and instead their next method just throws StopIteration at
the end? :)
Ugh. Out of curiosity, how does a Python programmer manage
multiple "parallel" iterations?
The builtin 'map' function takes a variable number of iterable things as
parameters; it combines them into a sequence of tuples, with one element
from each iterable, before applying a function to them. It pads shorter
iterables with None (python's version of null). If the function is None,
the identity function is used.
So (>>> being the interpreter prompt):
boys = ['Guido', 'Tim', 'Fredrik']
girls = ['Patricia', 'Sara'] # sorry, don't know any pythonesses!
map(None, boys, girls)
[('Guido', 'Patricia'), ('Tim', 'Sara'), ('Fredrik', None)]
You generally don't operate directly on iterators in python, but if you
wanted to, iterators are iterable, so:
map(None, iter(boys), iter(girls))
[('Guido', 'Patricia'), ('Tim', 'Sara'), ('Fredrik', None)]
For your example:
for boy, girl in map(None, boys, girls):
.... print "%s\t%s" % tuple(map(lambda s: s or "", (boy, girl)))
....
Guido Patricia
Tim Sara
Fredrik
There, i've had to do a little map to turn the None into an empty string.
There may be a more elegant way to do that.
Still, doesn't compare badly to ...
List<Child> boys = ...;
List<Child> girls = ...;
Iterator<Child> ib = boys.iterator();
Iterator<Child> ig = girls.iterator();
while (ib.hasNext() || ig.hasNext()) {
if (ib.hasNext())
System.out.print(ib.next());
if (ig.hasNext()) {
System.out.print("\t"); // crude, but just for example
System.out.print(ig.next());
}
System.out.println();
}
... eh? <wink>
Now, however you use it, map() instantiates the result list, which if the
argument iterators are big is a bad move. There is an iterating version of
map, called imap, in the standard itertools package. However, it differs
from map in that it stops when the first iterable runs out, which makes it
useless for this. There's also a builtin called zip, and an iterating
version called izip, which do much the same as map with a None function,
both of which stop at the end of the shortest iterator. It's a real shame
there isn't an iterating longest-iterator version.
So here's one:
def izip2(*iters):
def take(i):
if (iters[i] == None):
return None
try:
obj = iters[i].next()
return obj
except StopIteration:
iters[i] = None
return None
iters = list(iters)
n = len(iters)
end = [None] * n
while (True):
row = map(take, xrange(n))
if (iters == end): return
yield row
With which:
for boy, girl in izip2(iter(boys), iter(girls)):
.... print "%s\t%s" % tuple(map(lambda s: s or "", (boy, girl)))
....
Guido Patricia
Tim Sara
Fredrik
I'm not convinced this function is all that great - my python's getting
quite rusty. Still, it's a generator expression with a nested function!
tom
--
People don't want nice. People want London. -- Al