# Understanding how maps work

## Problem

``````map(function, iterable, ...)
``````

Return a list of the results after applying the function to each item in the iterable. If more iterable arguments are supplied, the function must take that many arguments and apply them all at once to the items in all iterables.

It is anticipated that if one iterable is shorter than another, it will be extended using None items.

The identity function is assumed if function is None; if there are several parameters, map() returns a list of tuples containing the corresponding items from all iterables (a kind of transpose operation).

The iterable parameters can be a sequence or any iterable object, with a list as the result.

What role does this play in the creation of a Cartesian item?

``````content = map(tuple, array)
``````

What happens if you insert a tuple anywhere in there? I also noted that the result is abc without the map function and a, b, c with it.

I’d like to completely comprehend this function. The reference definitions are likewise difficult to comprehend. There’s a lot of fancy fluff here.

## Solution #1

``````map(f, iterable)
``````

is basically the same as:

``````[f(x) for x in iterable]
``````

Because the length of the output list is always the same as the length of the input list, map cannot produce a Cartesian product on its own. However, a Cartesian product can be easily accomplished with a list comprehension:

``````[(a, b) for a in iterable_a for b in iterable_b]
``````

The syntax is a little strange — it’s effectively the same as:

``````result = []
for a in iterable_a:
for b in iterable_b:
result.append((a, b))
``````

## Solution #2

Although I assume someone well-versed in functional programming may come up with some impossible-to-understand manner of producing one using map, map has nothing to do with Cartesian products.

This is what map in Python 3 looks like:

``````def map(func, iterable):
for i in iterable:
yield func(i)
``````

and the only difference in Python 2 is that it will build up a full list of results to return all at once instead of yielding.

Although, when using a lambda expression as the first parameter, Python tradition uses list comprehensions (or generator expressions) to get the same result as a call to map:

``````[func(i) for i in iterable]
``````

By ‘array,’ you probably mean either a tuple or a list (both of which act a little like arrays from other languages) – as an example of what you asked for in the comments on the topic – “convert a string into an array” –

`````` >>> a = "hello, world"
>>> list(a)
['h', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd']
>>> tuple(a)
('h', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd')
``````

If you start with a list of strings rather than a single string, you can use map to listify each one individually:

``````>>> a = ["foo", "bar", "baz"]
>>> list(map(list, a))
[['f', 'o', 'o'], ['b', 'a', 'r'], ['b', 'a', 'z']]
``````

Note that map(list, a) is identical in Python 2, but if you want to do anything other than feed it into a for loop in Python 3, you’ll need the list call (or a processing function such as sum that only needs an iterable, and not a sequence). However, keep in mind that comprehension of a list is usually preferred:

``````>>> [list(b) for b in a]
[['f', 'o', 'o'], ['b', 'a', 'r'], ['b', 'a', 'z']]
``````

## Solution #3

By applying a function to each member in the source, map generates a new list:

``````xs = [1, 2, 3]

# all of those are equivalent — the output is [2, 4, 6]
# 1. map
ys = map(lambda x: x * 2, xs)
# 2. list comprehension
ys = [x * 2 for x in xs]
# 3. explicit loop
ys = []
for x in xs:
ys.append(x * 2)
``````

n-ary map is equivalent to zipping input iterables together and then applying the transformation function on every element of that intermediate zipped list. It isn’t a Cartesian item:

``````xs = [1, 2, 3]
ys = [2, 4, 6]

def f(x, y):
return (x * 2, y // 2)

# output: [(2, 1), (4, 2), (6, 3)]
# 1. map
zs = map(f, xs, ys)
# 2. list comp
zs = [f(x, y) for x, y in zip(xs, ys)]
# 3. explicit loop
zs = []
for x, y in zip(xs, ys):
zs.append(f(x, y))
``````

I’ve used zip here, but map behaves differently when iterables aren’t the same size — it expands iterables to contain None, as indicated in its docs.

## Solution #4

To put it another way, map() may accomplish something like this:

``````def mymap(func, lst):
result = []
for e in lst:
result.append(func(e))
return result
``````

As you can see, it takes a function and a list, and returns a new list with the result of applying the function to each of the elements in the input list. I said “simplifying a bit” because in reality map() can process more than one iterable:

For the second half of the question: How does this contribute to the creation of a Cartesian product? map() might, for example, be used to create the cartesian product of a list like this:

``````lst = [1, 2, 3, 4, 5]

reduce(add, map(lambda i: map(lambda j: (i, j), lst), lst))
``````

… But to tell the truth, using product() is a much simpler and natural way to solve the problem:

``````from itertools import product
list(product(lst, lst))
``````

In either case, the cartesian product of lst, as stated above, is obtained:

``````[(1, 1), (1, 2), (1, 3), (1, 4), (1, 5),
(2, 1), (2, 2), (2, 3), (2, 4), (2, 5),
(3, 1), (3, 2), (3, 3), (3, 4), (3, 5),
(4, 1), (4, 2), (4, 3), (4, 4), (4, 5),
(5, 1), (5, 2), (5, 3), (5, 4), (5, 5)]
``````

## Solution #5

The map() method applies the same procedure to all items in an iterable data structure, such as lists, generators, strings, and other objects.

Consider the following example: map() can iterate over each item in a list and apply a function to each item before returning (returning) the new list.

Imagine you have a function that takes a number, adds 1 to that number and returns it:

``````def add_one(num):
new_num = num + 1
return new_num
``````

You also have a number list:

``````my_list = [1, 3, 6, 7, 8, 10]
``````

You can do the following to increment all of the numbers in the list:

``````>>> map(add_one, my_list)
[2, 4, 7, 8, 9, 11]
``````

Note: At minimum map() needs two arguments. First a function name and second something like a list.

Let’s have a look at what else map() can do. map() can take several iterables (lists, strings, etc.) and provide an element from each one as an input to a function.

We have three lists:

``````list_one = [1, 2, 3, 4, 5]
list_two = [11, 12, 13, 14, 15]
list_three = [21, 22, 23, 24, 25]
``````

You can use map() to create a new list that has the addition of elements at a given index.

Remember that map() requires a function. We’ll utilize the built-in sum() function this time. The following is the output of map():

``````>>> map(sum, list_one, list_two, list_three)
[33, 36, 39, 42, 45]
``````

REMEMBER: map() in Python 2 will iterate (go over the elements of the lists) according to the longest list, passing None to the function for the shorter lists, thus your function should look for None and handle them, or you’ll get problems. After completing the shortest list, map() in Python 3 will exit. Also, map() in Python 3 produces an iterator rather than a list.