# Getting a map() to return a list in Python 3.x

Posted on

Problem :

I’m trying to map a list into hex, and then use the list elsewhere. In python 2.6, this was easy:

A: Python 2.6:

``````>>> map(chr, [66, 53, 0, 94])
['B', '5', 'x00', '^']
``````

However, in Python 3.1, the above returns a map object.

B: Python 3.1:

``````>>> map(chr, [66, 53, 0, 94])
<map object at 0x00AF5570>
``````

How do I retrieve the mapped list (as in A above) on Python 3.x?

Alternatively, is there a better way of doing this? My initial list object has around 45 items and id like to convert them to hex.

Solution :

Do this:

``````list(map(chr,[66,53,0,94]))
``````

In Python 3+, many processes that iterate over iterables return iterators themselves. In most cases, this ends up saving memory, and should make things go faster.

If all you’re going to do is iterate over this list eventually, there’s no need to even convert it to a list, because you can still iterate over the `map` object like so:

``````# Prints "ABCD"
for ch in map(chr,[65,66,67,68]):
print(ch)
``````

New and neat in Python 3.5:

``````[*map(chr, [66, 53, 0, 94])]
``````

UPDATE

Always seeking for shorter ways, I discovered this one also works:

``````*map(chr, [66, 53, 0, 94]),
``````

Unpacking works in tuples too. Note the comma at the end. This makes it a tuple of 1 element. That is, it’s equivalent to `(*map(chr, [66, 53, 0, 94]),)`

It’s shorter by only one char from the version with the list-brackets, but, in my opinion, better to write, because you start right ahead with the asterisk – the expansion syntax, so I feel it’s softer on the mind. 🙂

Why aren’t you doing this:

``````[chr(x) for x in [66,53,0,94]]
``````

It’s called a list comprehension. You can find plenty of information on Google, but here’s the link to the Python (2.6) documentation on list comprehensions. You might be more interested in the Python 3 documenation, though.

List-returning map function has the advantage of saving typing, especially during interactive sessions. You can define `lmap` function (on the analogy of python2’s `imap`) that returns list:

``````lmap = lambda func, *iterable: list(map(func, *iterable))
``````

Then calling `lmap` instead of `map` will do the job:
`lmap(str, x)` is shorter by 5 characters (30% in this case) than `list(map(str, x))` and is certainly shorter than `[str(v) for v in x]`. You may create similar functions for `filter` too.

There was a comment to the original question:

I would suggest a rename to Getting map() to return a list in Python 3.* as it applies to all Python3 versions. Is there a way to do this? – meawoppl Jan 24 at 17:58

It is possible to do that, but it is a very bad idea. Just for fun, here’s how you may (but should not) do it:

``````__global_map = map #keep reference to the original map
lmap = lambda func, *iterable: list(__global_map(func, *iterable)) # using "map" here will cause infinite recursion
map = lmap
x = [1, 2, 3]
map(str, x) #test
map = __global_map #restore the original map and don't do that again
map(str, x) #iterator
``````

Converting my old comment for better visibility: For a “better way to do this” without `map` entirely, if your inputs are known to be ASCII ordinals, it’s generally much faster to convert to `bytes` and decode, a la `bytes(list_of_ordinals).decode('ascii')`. That gets you a `str` of the values, but if you need a `list` for mutability or the like, you can just convert it (and it’s still faster). For example, in `ipython` microbenchmarks converting 45 inputs:

``````>>> %%timeit -r5 ordinals = list(range(45))
... list(map(chr, ordinals))
...
3.91 µs ± 60.2 ns per loop (mean ± std. dev. of 5 runs, 100000 loops each)

>>> %%timeit -r5 ordinals = list(range(45))
... [*map(chr, ordinals)]
...
3.84 µs ± 219 ns per loop (mean ± std. dev. of 5 runs, 100000 loops each)

>>> %%timeit -r5 ordinals = list(range(45))
... [*bytes(ordinals).decode('ascii')]
...
1.43 µs ± 49.7 ns per loop (mean ± std. dev. of 5 runs, 1000000 loops each)

>>> %%timeit -r5 ordinals = list(range(45))
... bytes(ordinals).decode('ascii')
...
781 ns ± 15.9 ns per loop (mean ± std. dev. of 5 runs, 1000000 loops each)
``````

If you leave it as a `str`, it takes ~20% of the time of the fastest `map` solutions; even converting back to list it’s still less than 40% of the fastest `map` solution. Bulk convert via `bytes` and `bytes.decode` then bulk converting back to `list` saves a lot of work, but as noted, only works if all your inputs are ASCII ordinals (or ordinals in some one byte per character locale specific encoding, e.g. `latin-1`).

``````list(map(chr, [66, 53, 0, 94]))
``````

map(func, *iterables) –> map object
Make an iterator that computes the function using arguments from
each of the iterables. Stops when the shortest iterable is exhausted.

“Make an iterator”

means it will return an iterator.

“that computes the function using arguments from each of the iterables”

means that the next() function of the iterator will take one value of each iterables and pass each of them to one positional parameter of the function.

So you get an iterator from the map() funtion and jsut pass it to the list() builtin function or use list comprehensions.

In addition to above answers in `Python 3`, we may simply create a `list` of result values from a `map` as

``````li = []
for x in map(chr,[66,53,0,94]):
li.append(x)

print (li)
>>>['B', '5', 'x00', '^']
``````

We may generalize by another example where I was struck, operations on map can also be handled in similar fashion like in `regex` problem, we can write function to obtain `list` of items to map and get result set at the same time. Ex.

``````b = 'Strings: 1,072, Another String: 474 '
li = []
for x in map(int,map(int, re.findall('d+', b))):
li.append(x)

print (li)
>>>[1, 72, 474]
``````

Using list comprehension in python and basic map function utility, one can do this also:

`chi = [x for x in map(chr,[66,53,0,94])]`

You can try getting a list from the map object by just iterating each item in the object and store it in a different variable.

``````a = map(chr, [66, 53, 0, 94])
b = [item for item in a]
print(b)
>>>['B', '5', 'x00', '^']
``````

Another option is to create a shortcut, returning a list:

``````from functools import reduce
_compose = lambda f, g: lambda *args: f(g(*args))
lmap = reduce(_compose, (list, map))

>>> lmap(chr, [66, 53, 0, 94])
['B', '5', 'x00', '^']
``````

``````#Devil
input_list = [66, 53, 0, 94]
out = [chr(x) for x in input_list]
print(out)

# you will get the desire output in out list
# ['B', '5', 'x00', '^']

#------------------------------
#To retrieve your list use 'ord'

original_list = [ord(x) for x in out]
print(original_list )
#[66, 53, 0, 94]
``````