在Python中,修改一个大列表而不使用任何循环

8

我的列表如下:

a=[1,2,3,4]

现在我希望我的列表是这样的:
a=[-1,-2,-3,-4]

如何在不使用任何循环的情况下改变我的列表?

更新:这可能是一个很大的列表,大约有10000个元素。


你为什么认为单循环遍历10000个整数是瓶颈问题?那真的不会花费太长时间。 - Aaron Dufour
请注意,使用“map”和“lambda”的答案将比仅循环慢。仅“不循环”本身并不能使您的代码更快。 - Duncan
也许你应该考虑不使用否定的方式,那么你能告诉我为什么想要否定以及在这种情况下为什么循环会更慢吗? - Anurag Uniyal
值得思考:http://en.wikipedia.org/wiki/Loop_unwinding(可能不适用于Python) - Matt Fenwick
相关链接:极速优化异或操作数组 https://dev59.com/yHI95IYBdhLWcg3w2h56 - John La Rooy
显示剩余3条评论
8个回答

14

使用Python的map功能

a[:] = map(lambda x: -x, a)

这是来自上面链接的map函数描述: map(function, iterable, ...) 将函数应用于iterable的每个项,并返回结果列表。如果传递了额外的可迭代参数,则函数必须取得那么多的参数,并且并行地应用于所有可迭代对象中的项。如果一个可迭代对象比另一个短,那么它被认为是扩展了None项。如果函数为None,则假定为身份函数;如果有多个参数,则map()返回一个列表,其中包含所有可迭代对象的相应项的元组(一种转置操作)。可迭代参数可以是序列或任何可迭代对象;结果始终是一个列表。

2
这不会直接修改现有的列表,而是用答案取反的新列表替换变量a。(当然,这可能对OP来说是可以接受的,但这是一个微妙的区别。) - millimoose
1
它比循环或列表推导式快得多吗? - Anurag Uniyal
4
如果你使用 a[:] = ... 而不是 a = ... 进行赋值,那么通过切片赋值将直接在原列表上进行修改。这样做会导致其他引用该列表的地方也看到了被取反后的值。 - PaulMcG
1
@PaulMcGuire 谢谢,我不知道这一点,已经相应地更新了我的答案。 - Bobby
Alex Martelli在他对这个问题的回答中向我展示了光明:https://dev59.com/p3M_5IYBdhLWcg3w1G6N - PaulMcG
由于您正在使用地图,最好直接使用函数而不是lambda。 import operator 然后 a[:] = map(operator.neg, a) 这样在性能方面更好。 - TMC

9

以下是来自IPython的一些简单而快速的基准测试结果:

In [1]: a=range(10000)

In [2]: import numpy 

In [3]: timeit [-i for i in a]
1000 loops, best of 3: 576 us per loop

In [4]: timeit map(lambda i:-i, a)
1000 loops, best of 3: 1.68 ms per loop

In [5]: timeit list(-1*numpy.array(a))
100 loops, best of 3: 2.53 ms per loop

请注意,如果a可以是numpy数组,则无需浪费时间进行转换。
In [6]: a = numpy.array(a)

In [7]: timeit -- -a
100000 loops, best of 3: 15.4 us per loop

4
你可以使用numpy库:
list(-1*numpy.array(a))

不幸的是,Python和numpy之间的转换开销使其不适合加速单次操作。 - John La Rooy

3

这取决于你所说的没有任何循环是什么意思。如果你只是想避免显式的循环,比如

a = [ -x for x in a ]

你可以使用map函数,它会为你循环。
a = map( lambda x:-x, a)

3
import operator
a = map(operator.neg, a)

请注意,与其他使用“map”的答案不同,这个答案可能比显式循环更快。其他“map”答案都使用了一个“lambda”,这会使它们变慢。 - Duncan

1

你不能没有循环来完成它,但你可以隐藏这个事实。

map(lambda x: -x, a)

1

不知道为什么不需要循环,也知道没有其他有效的方法来否定一个列表,在这里是我的超级快速解决方案(我对上下文没有了解,所以可能不起作用)

class nlist(object):
    def __init__(self, l):
        self._list = l

    def __getitem__(self, key):
        return -self._list[key]

    def __iter__(self):
        for i in self._list:
            yield -i


nl = nlist([1,2,3,4])
for i in nl:
    print i

0
a = [-a[0], -a[1], -a[2], -a[3]]

现在的问题是,这只适用于a恰好有4个项目的情况。要推广到不同数量的项目......那就需要使用循环。

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