Modifying every alternate element of a sequence

Discussion in 'Python' started by jm.suresh@no.spam.gmail.com, Nov 28, 2006.

  1. Guest

    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
    , Nov 28, 2006
    #1
    1. Advertising

  2. Tim Chase Guest

    > 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
    does your comparison work:

    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
    Tim Chase, Nov 28, 2006
    #2
    1. Advertising

  3. John Hicken Guest

    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
    John Hicken, Nov 28, 2006
    #3
  4. Leo Kislov Guest

    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
    Leo Kislov, Nov 28, 2006
    #4
  5. On 2006-11-28, <> 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
    Antoon Pardon, Nov 28, 2006
    #5
  6. Guest

    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:
    > 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
    , Nov 28, 2006
    #6
  7. 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
    Roberto Bonvallet, Nov 28, 2006
    #7
  8. On Tue, 28 Nov 2006 02:38:09 -0800, 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.
    Steven D'Aprano, Nov 28, 2006
    #8
  9. Leo Kislov Guest

    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
    Leo Kislov, Nov 28, 2006
    #9
  10. Guest

    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
    , Nov 28, 2006
    #10
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Sean Burns

    Alternate to Sequence?

    Sean Burns, Jan 23, 2006, in forum: XML
    Replies:
    1
    Views:
    365
    Stan Kitsis [MSFT]
    Jan 23, 2006
  2. Chris
    Replies:
    2
    Views:
    665
    Chris
    Mar 4, 2007
  3. Neal Becker
    Replies:
    1
    Views:
    230
    Alex Martelli
    Sep 2, 2007
  4. =?Utf-8?B?SXJ3YW5zeWFo?=
    Replies:
    4
    Views:
    2,435
    =?Utf-8?B?SXJ3YW5zeWFo?=
    Oct 30, 2007
  5. Replies:
    10
    Views:
    323
    Sean O'Halpin
    Jul 17, 2006
Loading...

Share This Page