Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   Python (http://www.velocityreviews.com/forums/f43-python.html)
-   -   Modifying every alternate element of a sequence (http://www.velocityreviews.com/forums/t396789-modifying-every-alternate-element-of-a-sequence.html)

 jm.suresh@no.spam.gmail.com 11-28-2006 10:38 AM

Modifying every alternate element of a sequence

I have a list of numbers and I want to build another list with every
second element multiplied by -1.

input = [1,2,3,4,5,6]
wanted = [1,-2,3,-4,5,-6]

I can implement it like this:

input = range(3,12)
wanted = []
for (i,v) in enumerate(input):
if i%2 == 0:
wanted.append(v)
else:
wanted.append(-v)

But is there any other better way to do this.

--
Suresh

 Tim Chase 11-28-2006 11:18 AM

Re: Modifying every alternate element of a sequence

> I have a list of numbers and I want to build another list with every
> second element multiplied by -1.
>
> input = [1,2,3,4,5,6]
> wanted = [1,-2,3,-4,5,-6]
>
> I can implement it like this:
>
> input = range(3,12)
> wanted = []
> for (i,v) in enumerate(input):
> if i%2 == 0:
> wanted.append(v)
> else:
> wanted.append(-v)

>>> input = range(3,12)
>>> [i%2==0 and v or -v for (i,v) in enumerate(input)]

[3, -4, 5, -6, 7, -8, 9, -10, 11]

> But is there any other better way to do this.

I'm not sure densely packing it into a list comprehension is
necessarily a *better* way, just a more compact way.

To make more sense of it, you might create a helper function that

def inv_if(v, test):
if test:
return v
else:
return -v

[inv_if(v, i%2==0) for (i,v) in enumerate(input)]

Or you could even do something like

def inv_alternating(t):
i, v = t
if i%2==0:
return v
else:
return -v

[inv_alternating(t) for t in enumerate(input)]

Either compacts it for the actual call within a list
comprehension, but it is cleaner to read what's going on.

-tkc

 John Hicken 11-28-2006 11:21 AM

Re: Modifying every alternate element of a sequence

jm.suresh@no.spam.gmail.com wrote:
> I have a list of numbers and I want to build another list with every
> second element multiplied by -1.
>
> input = [1,2,3,4,5,6]
> wanted = [1,-2,3,-4,5,-6]
>
> I can implement it like this:
>
> input = range(3,12)
> wanted = []
> for (i,v) in enumerate(input):
> if i%2 == 0:
> wanted.append(v)
> else:
> wanted.append(-v)
>
> But is there any other better way to do this.
>
> --
> Suresh

I would tend to do this as a list comprehension. In python 2.5 you can
do this:

wanted = [(v if i % 2 == 0 else -v) for (i,v) in enumerate(input)]

(a if b else c) is new to Python 2.5. You don't always need the
brackets, but I think it makes things clearer. See
(http://docs.python.org/whatsnew/pep-308.html) for more details on this
feature.

With earlier versions, you could do

wanted = [v - 2*(i % 2) for (i,v) in enumerate(input)]

That looks less clear to me than your version, though.

John Hicken

 Leo Kislov 11-28-2006 11:26 AM

Re: Modifying every alternate element of a sequence

jm.suresh@no.spam.gmail.com wrote:
> I have a list of numbers and I want to build another list with every
> second element multiplied by -1.
>
> input = [1,2,3,4,5,6]
> wanted = [1,-2,3,-4,5,-6]
>
> I can implement it like this:
>
> input = range(3,12)
> wanted = []
> for (i,v) in enumerate(input):
> if i%2 == 0:
> wanted.append(v)
> else:
> wanted.append(-v)
>
> But is there any other better way to do this.

Use slices:

input[1::2] = [-item for item in input[1::2]]

If you don't want to do it in-place, just make a copy:

wanted = input[:]
wanted[1::2] = [-item for item in wanted[1::2]]

-- Leo

 Antoon Pardon 11-28-2006 11:36 AM

Re: Modifying every alternate element of a sequence

On 2006-11-28, jm.suresh@no.spam.gmail.com <jm.suresh@gmail.com> wrote:
> I have a list of numbers and I want to build another list with every
> second element multiplied by -1.
>
> input = [1,2,3,4,5,6]
> wanted = [1,-2,3,-4,5,-6]
>
> I can implement it like this:
>
> input = range(3,12)
> wanted = []
> for (i,v) in enumerate(input):
> if i%2 == 0:
> wanted.append(v)
> else:
> wanted.append(-v)
>
> But is there any other better way to do this.

Wether this is better, I'll leave that for others to decide. But this
is a possibility:

wanted = [ (1 - 2*(i%2)) * item for i, item in enumerate(input)]

--
Antoon Pardon

 jm.suresh@no.spam.gmail.com 11-28-2006 12:02 PM

Re: Modifying every alternate element of a sequence

Wow, I was in fact searching for this syntax in the python tutorial. It
is missing there.
Is there a reference page which documents all possible list
comprehensions.
--
Suresh
Leo Kislov wrote:
> jm.suresh@no.spam.gmail.com wrote:
> > I have a list of numbers and I want to build another list with every
> > second element multiplied by -1.
> >
> > input = [1,2,3,4,5,6]
> > wanted = [1,-2,3,-4,5,-6]
> >
> > I can implement it like this:
> >
> > input = range(3,12)
> > wanted = []
> > for (i,v) in enumerate(input):
> > if i%2 == 0:
> > wanted.append(v)
> > else:
> > wanted.append(-v)
> >
> > But is there any other better way to do this.

>
> Use slices:
>
> input[1::2] = [-item for item in input[1::2]]
>
> If you don't want to do it in-place, just make a copy:
>
> wanted = input[:]
> wanted[1::2] = [-item for item in wanted[1::2]]
>
> -- Leo

 Roberto Bonvallet 11-28-2006 12:14 PM

Re: Modifying every alternate element of a sequence

jm.suresh@no.spam.gmail.com wrote:
> I have a list of numbers and I want to build another list with every
> second element multiplied by -1.

[...]
> But is there any other better way to do this.

I think the best way is the one that uses slices, as somebody suggested
in this thread. This is another (worse) way, just for fun:

>>> from itertools import cycle
>>> input = [1, 2, 3, 4, 5, 6]
>>> wanted = [x * sign for x, sign in zip(input, cycle([1, -1]))]
>>> wanted

[1, -2, 3, -4, 5, -6]

Cheers,
--
Roberto Bonvallet

 Steven D'Aprano 11-28-2006 12:24 PM

Re: Modifying every alternate element of a sequence

On Tue, 28 Nov 2006 02:38:09 -0800, jm.suresh@no.spam.gmail.com wrote:

> I have a list of numbers and I want to build another list with every
> second element multiplied by -1.
>
> input = [1,2,3,4,5,6]
> wanted = [1,-2,3,-4,5,-6]
>
> I can implement it like this:
>
> input = range(3,12)
> wanted = []
> for (i,v) in enumerate(input):
> if i%2 == 0:
> wanted.append(v)
> else:
> wanted.append(-v)
>
> But is there any other better way to do this.

Lots of ways.

Other people have given you some solutions. In my opinion, this is
the simplest method of all, if you want to modify input in place:

for i in range(1, len(input), 2):
input[where] = -input[where]

Here's another method that only works if there are an even number of items:

A = input[0::2] # extended slicing
B = input[1::2]
B = [-x for x in B]
tmp = zip(A, B) # but watch out for odd number of items!
result = []
for t in tmp:
result.extend(t)

Here's a third method:

factors = [(-1)**i for i in range(len(input))]
output = map(operator.mul, input, factors)

As for which is best, I leave that to you to decide.

--
Steven.

 Leo Kislov 11-28-2006 12:30 PM

Re: Modifying every alternate element of a sequence

jm.suresh@no.spam.gmail.com wrote:
> Wow, I was in fact searching for this syntax in the python tutorial. It
> is missing there.
> Is there a reference page which documents all possible list
> comprehensions.

There is actually only two forms of list comprehensions:
http://docs.python.org/ref/lists.html
[blah for x in expr] and [blah for x in expr if cond]

And here is reference page for slicing (note, it's not list
comprehension): http://docs.python.org/ref/slicings.html

-- Leo

 bearophileHUGS@lycos.com 11-28-2006 08:08 PM

Re: Modifying every alternate element of a sequence

Leo Kislov:
> input[1::2] = [-item for item in input[1::2]]
> If you don't want to do it in-place, just make a copy:
> wanted = input[:]
> wanted[1::2] = [-item for item in wanted[1::2]]

Very nice solution.
I have tried few versions like:
from itertools import imap, islice
from operator import neg
1) data[1::2] = [-el for el in data[1::2]]
2) data[1::2] = map(neg, data[1::2])
3) data[1::2] = imap(neg, data[1::2])
4) data[1::2] = map(neg, islice(data, 1, None, 2))
5) etc.

With Python 2.5 it seems that the n.2 (map + slicing) is the faster.

Bye,
bearophile

 All times are GMT. The time now is 02:44 PM.