在Python中有没有map的就地等效?

16 投票
4 回答
19287 浏览
提问于 2025-04-16 06:52

我有一串字符串,需要对它们进行清理。我已经有了一个清理它们的方法,所以我可以直接这样做:

new_list = map(Sanitize, old_list)

不过我不需要保留旧的列表。这让我想知道有没有什么方法可以直接在原地处理这些字符串,就像使用map那样。写个for循环来处理这个问题很简单(或者写一个自定义的原地map方法),但有没有什么现成的工具可以用呢?

4 个回答

5

我觉得你能做到的最接近的就是这个:

>>> x = ["1", "2", "3", "4"]
>>> x[:] = map(int, x)

这里所说的“就地修改”是指它会直接改变对象 x,而不是单纯地重新赋值。不过,它还是会创建一个单独的临时 map 对象(在 Python 2 中是列表)。所以,你的内存使用量会稍微多一点。下面我会解释这个是怎么回事。


类似于使用 this[0] = something,你也可以指定切片:

>>> x = [1, 2, 3, 4]
>>> x[1:3] = [0, 0]
>>> x
[1, 0, 0, 4]

因为切片可以省略某些部分(开始、结束或步长),你可以通过类似这样的方式来改变整个列表:

>>> x = [1, 2, 3, 4]
>>> x[:] = [4, 5, 6]
>>> x
[4, 5, 6]

如上所示,这种方式甚至可以改变列表的长度。下面可以看到,这确实是在改变实际的对象,而不是重新定义变量:

>>> x = [1, 2, 3, 4]
>>> y = x
>>> x[:] = [3, 4]
>>> y
[3, 4]

在赋值的右边不一定非得是一个列表。任何可迭代的对象都可以放在那一边。实际上,你甚至可以使用生成器:

>>> x = ["1", "2", "3", "4"]
>>> x[:] = (int(y) for y in x)
>>> x
[1, 2, 3, 4]

或者使用 map() 的返回值(在 Python 2 中是列表;在 Python 3 中是 map 对象):

>>> x = ["1", "2", "3", "4"]
>>> x[:] = map(int, x)
6

你需要使用循环:

for i in range(len(old_list)):
    old_list[i] = Sanitize(old_list[i])

没有现成的解决方案。

正如评论中提到的:可以写一个函数,按照提问者的需求来实现:

def map_in_place(fn, l):
    for i in range(len(l)):
        l[i] = fn(l[i])

map_in_place(Sanitize, old_list)
13

答案很简单:没有。

像“XXX存在吗”这样的问题,当答案是没有时,通常不会直接回答,所以我想把这个说出来。

大多数的 itertools 辅助工具和内置函数都是针对通用的迭代器工作的。比如 mapfilter、列表推导式和 for 循环——它们都是在迭代器上操作,而不是修改原来的容器(如果有的话)。

为什么在这个类别里没有任何可以改变内容的函数呢?因为没有一种通用的方法可以根据键和值来给容器赋值。举个例子,基本的字典迭代器(for x in {})是遍历键的,而给字典赋值时是用字典的结果作为 [] 的参数。相对的,列表是遍历的,赋值时用的是隐含的索引。由于底层的一致性不足,无法提供这样的通用函数,所以在 itertools 或内置函数里没有类似的东西。

理论上可以把它作为 listdict 的方法提供,但目前并没有。你只能自己实现了。

撰写回答