Python:原地映射

18

我在想是否有一种方法可以对某个对象运行map函数。 map函数的工作方式是将可迭代对象中的每个项应用于一个函数,生成一个列表。是否有一种方法使map函数修改可迭代对象本身?


你只能通过使用可变序列(即列表),而不是任意迭代器,在Python中高效地完成这项任务。 - jemfinch
1
没错,我正在使用一个列表。 - johannix
4个回答

15

如果需要就地修改列表,使用切片赋值通常是可以的。

mylist[:] = map(func, mylist)

这种方法有什么缺点吗?从内存角度来看,它几乎与 for i, item in enumerate(mylist): mylist[i] = func(item) 相同吗? - warvariuc
@warvariuc,你也可以使用生成器表达式mylist[:] = (func(item) for item in mylist)。如果你已经在其他地方定义了func,那么应该选择更易读的方式。 - John La Rooy
但是 mylist[:] = map(func, mylist)mylist[:] = (func(item) for item in mylist) 是否等同于 for i, item in enumerate(mylist): mylist[i] = func(item) - warvariuc
1
@warvariuc,是的,它们多多少少是等价的。 - John La Rooy
我会简单地使用 mylist = list(map(func, mylist)) - kakyo
这个在 bigO 空间复杂度方面并没有被考虑进去,是吗?尽管不是很清楚,但这可能是问题的本意。map 函数首先计算第二个列表,然后将整个列表分配给之前的位置。但在赋值之前,这两个列表同时存在于内存中。 - Kaio

4

这段代码很简单:

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

这在逻辑上是正确的,但我想使用 map 来提高性能... - johannix
我认为你已经无法从中获得更多性能了。如果你想要并行化,由于 GIL 的存在,你无法使用 Python 原地进行操作。 - carl

1
你可以使用lambda(或def),或者更好的列表推导式(如果足够的话):
[ do_things_on_iterable for item in iterable ]

无论如何,如果事情变得太复杂,您可能希望使用for循环更明确。

例如,您可以做类似的事情,但在我看来它很丑陋:

[ mylist.__setitem__(i,thing) for i,thing in enumerate(mylist) ]

1

只需编写明显的代码即可完成它。

for i, item in enumerate(sequence):
    sequence[i] = f(item)

列表推导式 == 对 map 的语法糖 - carl
2
那你如何解释性能下降呢?map 函数的速度大约慢了两倍。 - johannix
1
@cvondrick 列表推导式是 for 循环的语法糖,而不是 map 函数的。 - jemfinch
1
@jemfinch 如果是微秒,我显然不会在意。我正在处理一个大列表,我们谈论的时间差是以秒为单位的,这显然很重要... - johannix
考虑使用以下形式: for i in xrange(len(sequence)): sequence[i] = f(sequence[i]) 而不是你答案中的循环。这种形式不会为每个项目创建元组对象,也更能清晰地表达你的意图——迭代序列。 - Oleg Lokshyn
显示剩余6条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接