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...
Python 3 is definitely more readable, easier to grasp, and popular than Python 2. Python 2 has definitely run out of steam and one should learn Python 2 if and only if some legacy code has been written in Python 2 or if a company needs the developer to migrate the Python 2 code into Python 3.
Python 3 is more in-demand and includes a typing system. Python 2 is outdated and uses an older syntax for the print function. While Python 2 is still in use for configuration management in DevOps, Python 3 is the current standard. Python (the code, not the snake) is a popular coding language to learn for beginners.
If you want to determine whether Python2 or Python3 is running, you can check the major version with this sys. version_info. major . 2 means Python2, and 3 means Python3.
Python 3.3 comes faster than Python 2.7.
itertools.zip_longest does what you want, with a more comprehensible name. :)
I'll answer my own question this time.
With Python 3x, you can use itertools.zip_longest like so:
>>> list(map(lambda *a: a,*zip(*itertools.zip_longest(range(5),range(10,17)))))
[(0, 10), (1, 11), (2, 12), (3, 13), (4, 14), (None, 15), (None, 16)]
You can also roll ur own I suppose:
>>> def oldMapNone(*ells):
... '''replace for map(None, ....), invalid in 3.0 :-( '''
... lgst = max([len(e) for e in ells])
... return list(zip(* [list(e) + [None] * (lgst - len(e)) for e in ells]))
...
>>> oldMapNone(range(5),range(10,12),range(30,38))
[(0, 10, 30), (1, 11, 31), (2, None, 32), (3, None, 33), (4, None, 34), (None, None, 35), (None, None, 36), (None, None, 37)]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With