I was wondering if there is a way to run map on something. The way map works is it takes an iterable and applies a function to each item in that iterable producing a list. Is there a way to have map modify the iterable object itself?
Asked
Active
Viewed 1.7k times
18
-
You can only efficiently do this in Python with a mutable sequence (i.e., a list), not an arbitrary iterable. – jemfinch Jun 08 '10 at 19:28
-
1Right, I am working with a list. – johannix Jun 08 '10 at 19:30
4 Answers
15
A slice assignment is often ok if you need to modify a list in place
mylist[:] = map(func, mylist)

John La Rooy
- 295,403
- 53
- 369
- 502
-
What drawbacks does this approach have? From memory point of view it's the almost same as `for i, item in enumerate(mylist): mylist[i] = func(item)`? – warvariuc Apr 19 '18 at 10:45
-
@warvariuc, you can also use a generator expression `mylist[:] = (func(item) for item in mylist)`. If you already have `func` defined somewhere you should just choose whichever is more readable. – John La Rooy Apr 19 '18 at 14:57
-
But are `mylist[:] = map(func, mylist)` and `mylist[:] = (func(item) for item in mylist)` equivalent to `for i, item in enumerate(mylist): mylist[i] = func(item)`? – warvariuc Apr 20 '18 at 05:26
-
1
-
-
This isn't in place as far as bigO space complexity is concerned, is it? This is probably what the question was intending, even though it's not very clear. The map function first computes the second list and then assigns the whole list to the place where the list was before. But before the assignment the two lists are in memory simultaneously. – Kaio May 25 '22 at 15:39
4
It's simple enough to write:
def inmap(f, x):
for i, v in enumerate(x):
x[i] = f(v)
a = range(10)
inmap(lambda x: x**2, a)
print a

carl
- 49,756
- 17
- 74
- 82
-
That is logically correct, but I wanted to use map for performance gains... – johannix Jun 08 '10 at 19:26
-
I don't think you can squeeze much more performance out of this. If you want to parallelize it, you wouldn't be able to do it in place with Python due to the GIL. – carl Jun 08 '10 at 19:27
1
You can use a lambda (or a def) or better list comprehension (if it is sufficient):
[ do_things_on_iterable for item in iterable ]
Anyway you may want to be more explicit with a for loop if the things become too much complex.
For example you can do something like, that but imho it's ugly:
[ mylist.__setitem__(i,thing) for i,thing in enumerate(mylist) ]

pygabriel
- 9,840
- 4
- 41
- 54
1
Just write the obvious code to do it.
for i, item in enumerate(sequence):
sequence[i] = f(item)
-
I already tried that...oddly it's slower than the list comprehension. The reason I asked this question is because I figured map would be quicker than the list comprehension way, and also I don't see the point in creating a new list, but so far the list comprehension is winning. – johannix Jun 08 '10 at 19:25
-
-
2How do you explain the performance hit then? map was about twice as slow. – johannix Jun 08 '10 at 19:26
-
Stop caring about unimportant minor variations in speed. If you want to mutate the list, mutate the list, either with Paul's method above or cvondrick's function. Don't create a new list just because it happens to be microseconds faster. – jemfinch Jun 08 '10 at 19:29
-
1@cvondrick List comprehensions are syntactical sugar for a for loop, not for map. – jemfinch Jun 08 '10 at 19:32
-
@johannix The performance difference is because calling functions (especially lambdas) is slow(ish) in Python. Not that you should worry about that. – jemfinch Jun 08 '10 at 19:33
-
1@jemfinch If it were microseconds I clearly wouldn't care. I'm working on a big list, and the times we're talking about are seconds in difference, which clearly matters... – johannix Jun 08 '10 at 19:35
-
@johannix: You need to post full code then. The bottleneck is not in the map. If you must, parallelize it with multiprocessing.Pool.map. – carl Jun 08 '10 at 19:39
-
@johannix All the more reason to use this solution or cvondrick's, since the listcomp solution allocates way more memory and thus significantly limits the size of the lists you can process. – jemfinch Jun 08 '10 at 20:01
-
@cvondrick: just checked out the multiprocessing stuff. Didn't know about it. Surprisingly in my case parallelizing doesn't seem to help much. I did some quick tests and where the parallelizing paid off was when the processing you did on each item is very time intensive. – johannix Jun 10 '10 at 20:10
-
Consider using for i in xrange(len(sequence)): sequence[i] = f(sequence[i]) instead of the loop in your answer. This form does not create a tuple object for each item and also better illustrates your intent - to iterate over sequence – Oleg Lokshyn May 02 '16 at 19:45