In Python 2, a common (old, legacy) idiom is to use map
to join iterators of uneven length using the form map(None,iter,iter,...)
like so:
>>> map(None,xrange(5),xrange(10,12))
[(0, 10), (1, 11), (2, None), (3, None), (4, None)]
In Python 2, it is extended so that the longest iterator is the length of the returned list and if one is shorter than the other it is padded with None
.
In Python 3, this is different. First, you cannot use None
as an argument for the callable in position 1:
>>> list(map(None, range(5),range(10,12)))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'NoneType' object is not callable
OK -- I can fix that like so:
>>> def f(*x): return x
...
>>> list(map(f, *(range(5),range(10,12))))
[(0, 10), (1, 11)]
But now, I have a different problem: map
returns the shortest iterator's length -- no longer padded with None
.
As I port Python 2 code to Python 3, this is not a terrible rare idiom and I have not figured out an easy in place solution.
Unfortunately, the 2to3 tools does not pick this up -- unhelpfully suggesting:
-map(None,xrange(5),xrange(10,18))
+list(map(None,list(range(5)),list(range(10,18))))
Suggestions?
Edit
There is some discussion of how common this idiom is. See this SO post.
I am updating legacy code written when I was still in high school. Look at the 2003 Python tutorials being written and discussed by Raymond Hettinger with this specific behavior of map being pointed out...
itertools.zip_longest
does what you want, with a more comprehensible name. :)