8

My list is:

a=[1,2,3,4]

Now I want my list to be:

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

How can I change my list this way without using any loops?

Update: this may be a large list, on the order of 10000 elements.

Tamás
  • 47,239
  • 12
  • 105
  • 124
Froyo
  • 17,947
  • 8
  • 45
  • 73
  • Any special reason not to loop? – gecco Dec 08 '11 at 20:27
  • due to time constraints.. looping takes lots of time. I have to modify the list which has upto 10000 intergers – Froyo Dec 08 '11 at 20:36
  • Why do you think that a single loop over 10000 integers is your bottleneck issue? That really won't take very long. – Aaron Dufour Dec 08 '11 at 20:38
  • Note that the answers which use 'map' and a 'lambda' will be slower than just looping. Just 'not looping' won't by itself make your code faster. – Duncan Dec 08 '11 at 20:52
  • may be you should think of way to NOT negate, so may be can you tell why you want to negate and in that case why loop is slower? – Anurag Uniyal Dec 08 '11 at 20:54
  • Food for thought : http://en.wikipedia.org/wiki/Loop_unwinding (probably doesn't apply to python) – Matt Fenwick Dec 08 '11 at 21:04
  • @Matt, in extreme cases you might unroll a 10000 iteration loop (perhaps if timing is critical in an embedded system for example), but the space/time tradeoff usually isn't worth it beyond say 100. So to do 10000, you might loop through the unrolled part 100 times – John La Rooy Dec 08 '11 at 21:08
  • Related: extreme speedups to xor an array http://stackoverflow.com/questions/2119761/simple-python-challenge-fastest-bitwise-xor-on-data-buffers – John La Rooy Dec 08 '11 at 21:12

8 Answers8

14

Use Python's map functionality

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

Here's the description of the map function from the above link:

map(function, iterable, ...)
Apply function to every item of iterable and return a list of the results. If additional iterable arguments are passed, function must take that many arguments and is applied to the items from all iterables in parallel. If one iterable is shorter than another it is assumed to be extended with None items. If function is None, the identity function is assumed; if there are multiple arguments, map() returns a list consisting of tuples containing the corresponding items from all iterables (a kind of transpose operation). The iterable arguments may be a sequence or any iterable object; the result is always a list.

Bobby
  • 18,217
  • 15
  • 74
  • 89
  • 2
    This won't modify the existing list in place, it will replace the variable `a` with a new list with the answers negated. (Of course this might be acceptable to the OP, but it is a subtle difference.) – millimoose Dec 08 '11 at 20:17
  • 1
    is it significantly faster than loop or list comprehension? – Anurag Uniyal Dec 08 '11 at 20:54
  • 4
    If instead of assigning with `a = ...` you do `a[:] = ...`, then this *will* change the list in place, by doing a slice assignment. Then other references to this list will see the negated values. – PaulMcG Dec 08 '11 at 22:11
  • 1
    @PaulMcGuire Thanks I didn't know that, updated my answer accordingly. – Bobby Dec 08 '11 at 22:14
  • Alex Martelli showed me the light on this, in his answer to this question: http://stackoverflow.com/questions/1207406/remove-items-from-a-list-while-iterating-in-python – PaulMcG Dec 08 '11 at 22:17
  • Since you are using a map, it would be better to use a funciont directly instead of a lambda. `import operator` and then `a[:] = map(operator.neg, a)` Also is better in terms of performance. – TMC Nov 06 '19 at 18:55
9

some quick and dirty benchmarks from 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

Note that if a can be a numpy array you don't need to wast time on the conversion

In [6]: a = numpy.array(a)

In [7]: timeit -- -a
100000 loops, best of 3: 15.4 us per loop
John La Rooy
  • 295,403
  • 53
  • 369
  • 502
4

You can use the numpy library:

list(-1*numpy.array(a))
  • Unfortunately the overheads of converting between Python and numpy make it unsuitable for speeding up single shot operations like that – John La Rooy Dec 08 '11 at 20:55
3

Well it depends on what you mean by without any loops. In case you just want to avoid explicit loops like

a = [ -x for x in a ]

you could use the map function, that would loop for you.

a = map( lambda x:-x, a)
Joe M.
  • 609
  • 3
  • 11
3
import operator
a = map(operator.neg, a)
John La Rooy
  • 295,403
  • 53
  • 369
  • 502
  • Note that unlike the other answers which use `map` this answer is probably faster than an explicit loop. The other `map` answers all use a `lambda` which will make them slower. – Duncan Dec 08 '11 at 20:51
1

You cannot do it without loop but you can hide the fact.

map(lambda x: -x, a)
ILYA Khlopotov
  • 705
  • 3
  • 5
1

Without knowing the exact reason why loop is not required and knowing that there is no other efficient way to negate a list here is my super fast solution (I have no knowledge of the context so this may not work)

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
Anurag Uniyal
  • 85,954
  • 40
  • 175
  • 219
0
a = [-a[0], -a[1], -a[2], -a[3]]

Now the problem is that this only works if a has exactly 4 items. To generalise to different number of items...well that's what loops are for.

John La Rooy
  • 295,403
  • 53
  • 369
  • 502