Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multiple statements in list compherensions in Python?

Is it possible to have something like:

list1 = ...

currentValue = 0
list2 = [currentValue += i, i for i in list1]

I tried that but didn't work? What's the proper syntax to write those?

EDIT: the print statement was an example. Actually I am incrementing a value outside the loop.

like image 736
Joan Venge Avatar asked Apr 21 '09 22:04

Joan Venge


3 Answers

Statements cannot go inside of expressions in Python; it was a complication that was deliberately designed out of the language. For this problem, try using a complication that did make it into the language: generators. Watch:

def total_and_item(sequence):
    total = 0
    for i in sequence:
        total += i
        yield (total, i)

list2 = list(total_and_item(list1))

The generator keeps a running tally of the items seen so far, and prefixes it to each item, just like it looks like you example tries to do. Of course, a straightforward loop might be even simpler, that creates an empty list at the top and just calls append() a lot! :-)

like image 181
Brandon Rhodes Avatar answered Nov 11 '22 14:11

Brandon Rhodes


I'm not quite sure what you're trying to do but it's probably something like

list2 = [(i, i*2, i) for i in list1]
print list2

The statement in the list comprehension has to be a single statement, but you could always make it a function call:

def foo(i):
    print i
    print i * 2
    return i
list2 = [foo(i) for i in list1]
like image 4
David Z Avatar answered Nov 11 '22 13:11

David Z


As pjz said, you can use functions, so here you can use a closure to keep track of the counter value:

# defines a closure to enclose the sum variable
def make_counter(init_value=0):
    sum = [init_value]
    def inc(x=0):
        sum[0] += x
        return sum[0]
    return inc

Then you do what you want with list1:

list1 = range(5)  # list1 = [0, 1, 2, 3, 4]

And now with just two lines, we get list2:

counter = make_counter(10)  # counter with initial value of 10
list2 = reduce(operator.add, ([counter(x), x] for x in list1))

In the end, list2 contains:

[10, 0, 11, 1, 13, 2, 16, 3, 20, 4]

which is what you wanted, and you can get the value of the counter after the loop with one call:

counter()  # value is 20

Finally, you can replace the closure stuff by any kind of operation you want, here we have an increment, but it's really up to you. Note also that we use a reduce to flatten list2, and this little trick requires you to import operator before calling the line with the reduce:

import operator
like image 3
Manu Avatar answered Nov 11 '22 12:11

Manu