Why does the card work like izip_longest with fill = None?

When map has inputs of different lengths, the missing value is None :

 >>> x = [[1,2,3,4],[5,6]] >>> map(lambda *x:x, *x) [(1, 5), (2, 6), (3, None), (4, None)] 

This is the same behavior as:

 >>> import itertools >>> list(itertools.izip_longest(*x)) [(1, 5), (2, 6), (3, None), (4, None)] 

What is the reason map provides this behavior and not the following?

 >>> map(lambda *x:x, *x) [(1, 5), (2, 6), (3,), (4,)] 

... and is there an easy way to get the latest behavior with either some zip or map flavor?

+8
python dictionary zip
source share
2 answers

I think this is a design decision that kernel developers chose at the time they implemented map . There is no universally defined behavior for map when it is used with multiple iterators, quoting Map (higher order function) :

A card with two or more lists faces a processing problem when the lists have different lengths. In this, different languages ​​differ; some cause an exception, some stop after the length of the shortest list and ignore additional elements in other lists; some extend the length of the longest list, and for already completed lists, pass some placeholder value to a function that does not specify a value.

So, the Python core developers chose None as a placeholder for shorter iterations, while map was introduced in Python in 1993.

But in the case of itertools.imap it is a short circuit with the shortest iterable, because its design is strongly inspired by languages ​​such as Standard ML, Haskell and APL. In standard ML and Haskell map , the shortest iterable ends (I'm not sure about APL, though).

Python 3 also removed map(None, ...) (or should we say itertools.imap , Python 3 map is actually almost itertools.imap : Move map() from itertools to builtins ) because it was only present in Python 2 because at the time map added in Python in Python, there was no zip() function.

From Issue2186: map and filter should not support None as the first argument (only in Py3k) :

I agree with Guido that we would never create map(None, ...) if zip() . The main use case is out of date.


To get the result you want, I would suggest using itertools.izip_longest with the sentinel ( object() ) value, and not None by default, None will break things if the iterators themselves contain None :

 from itertools import izip_longest def solve(seq): sentinel = object() return [tuple(x for x in item if x is not sentinel) for item in izip_longest(*seq, fillvalue=sentinel)] print solve([[1,2,3,4],[5,6]]) # [(1, 5), (2, 6), (3,), (4,)] 
+5
source share

Given that the first list is always longer and that there are only two lists, you should do something like this:

 x = [1,2,3,4,5] y = ['a','b'] zip(x,y) + [(i,) for i in x[len(y):]] [(1, 'a'), (2, 'b'), (3,), (4,), (5,)] 
+1
source share

All Articles