Несколько утверждений в списках в Python? - PullRequest
10 голосов
/ 22 апреля 2009

Возможно ли иметь что-то вроде:

list1 = ...

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

Я пробовал это, но не сработало? Какой правильный синтаксис для их написания?

EDIT: оператор печати был примером. На самом деле я увеличиваю значение вне цикла.

Ответы [ 9 ]

26 голосов
/ 22 апреля 2009

Заявления не могут входить в выражения в Python; это было осложнение, которое было преднамеренно разработано вне языка. Для этой проблемы попробуйте использовать усложнение, которое сделал , сделало это на языке: generators. Смотреть:

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

list2 = list(total_and_item(list1))

Генератор отслеживает количество увиденных до сих пор элементов и добавляет к каждому элементу префикс, точно так же, как это выглядит в вашем примере. Конечно, простой цикл может быть еще проще, он создает пустой список сверху и просто вызывает append ()! : -)

3 голосов
/ 22 апреля 2009

Я не совсем уверен, что вы пытаетесь сделать, но это, вероятно, что-то вроде

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

Оператор в понимании списка должен быть одним оператором, но вы всегда можете сделать его вызовом функции:

def foo(i):
    print i
    print i * 2
    return i
list2 = [foo(i) for i in list1]
2 голосов
/ 22 июля 2009

Как сказал pjz, вы можете использовать функции, поэтому здесь вы можете использовать замыкание для отслеживания значения счетчика:

# 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

Затем вы делаете то, что вы хотите с list1:

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

И теперь, имея всего две строки, мы получаем list2:

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

В конце list2 содержит:

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

это то, что вы хотели, и вы можете получить значение счетчика после цикла одним вызовом:

counter()  # value is 20

Наконец, вы можете заменить закрывающий элемент любым видом операции, которую вы хотите, здесь у нас есть приращение, но это действительно ваше дело. Также обратите внимание, что мы используем редукцию к сглаживанию list2, и этот маленький трюк требует, чтобы вы импортировали оператор , прежде чем вызывать строку с редуктом:

import operator
2 голосов
/ 22 апреля 2009

Вот пример из другого вопроса :

[i for i,x in enumerate(testlist) if x == 1]

генератор перечисления возвращает 2-кортеж, который входит в i, x.

1 голос
/ 24 апреля 2009

Зачем вам создавать дубликат списка. Кажется, что все, что могло бы сделать понимание списка, это просто суммировать содержимое.

Почему бы не просто.

list2 = list(list1)   #this makes a copy
currentValue = sum(list2)
1 голос
/ 22 апреля 2009

Для вашего отредактированного примера:

currentValue += sum(list1)

или

for x in list1:
    currentValue += x

Понимание списков великолепно, я люблю их, но в скромном цикле for нет ничего плохого, и вы не должны бояться его использовать: -)

РЕДАКТИРОВАТЬ: «Но что, если я хочу увеличить значение, отличное от собранных значений?»

Ну, что вы хотите увеличить? В вашем распоряжении вся сила питона!

Увеличение на х-квадрат?

for x in list1:
    currentValue += x**2

Увеличение на некоторую функцию x и его положение в списке?

for i, x in enumerate(list1):
    currentValue += i*x
1 голос
/ 22 апреля 2009

Печать - странная вещь, которую нужно вызывать при понимании списка. Было бы полезно, если бы вы показали нам, какой вывод вы хотите, а не только код, который не работает.

Вот две догадки для вас. В любом случае, важным моментом является то, что оператор значения в понимании списка должен иметь значение single . Вы не можете вставить несколько элементов одновременно. (Если это то, что вы пытаетесь сделать, перейдите ко 2-му примеру.)

list1 = [1, 2, 3]
list2 = [(i, i*2, i) for i in list1]
# list2 = [(1, 2, 1), (2, 4, 2), (3, 6, 3)]

Чтобы получить плоский список:

list1 = [1, 2, 3]
tmp = [(i, i*2) for i in list1]
list2 = []
map(list2.extend, tmp)
# list2 = [1, 2, 1, 2, 4, 2, 3, 6, 3]

Edit: Увеличение значения в середине понимания списка все еще странно. Если вам действительно нужно это сделать, лучше написать обычный цикл for и добавлять значения по мере необходимости. В Python такая хитрость почти всегда обозначается как «не пифоническая». Сделайте это, если нужно, но на форумах, подобных этому, у вас не будет никаких проблем. ;)

1 голос
/ 22 апреля 2009

Прежде всего, вы, вероятно, не хотите использовать print. Он ничего не возвращает, поэтому используйте обычный цикл for, если вы просто хотите распечатать материал. То, что вы ищете:

>>> list1 = (1,2,3,4)
>>> list2 = [(i, i*2) for i in list1] # Notice the braces around both items
>>> print(list2)
[(1, 2), (2, 4), (3, 6), (4, 8)]
0 голосов
/ 22 апреля 2009

Вы не можете сделать несколько операторов, но вы можете сделать вызов функции. Чтобы сделать то, что вы хотите выше, вы можете сделать:

list1 = ...
list2 = [ (sum(list1[:i], i) for i in list1 ]

в общем, так как списочные выражения являются частью «функциональной» части python, вы ограничены ... функциями. Другие люди предложили, что вы можете написать свои собственные функции, если это необходимо, и это также допустимое предложение.

...