2017-02-21 22 views
4

У меня есть функция, которая возвращает два значения, и я хотел бы использовать понимание списка для заполнения двух списков. , например:python list comprehension для множественной функции возврата

def f(x): 
    return 2*x,x*x 

x = range(3) 
xlist, ylist = [f(value) for value in x] 

EDITS from answers below: 
xtuple, ytuple = zip(*[f(value) for value in x]) 
xlist, ylist = map(list,zip(*[f(value) for value in x])) 

где ожидаемый доход должен быть:

xlist = [0, 2, 4] 
ylist = [0, 1, 4] 

мой вопрос сводится к:

В настоящее время я получаю список кортежей, в то время как это разумно я закончу требующих двух независимых списков. в настоящее время у меня может быть переменная 1 placeholder (кортеж) и 3 полных понимания. Но мне интересно, есть ли чистый способ сделать это с использованием единого списка.

Стоит отметить: в реальном коде мои два возвращения коррелированы, поэтому я не могу просто разделить функцию на две.

+0

не следует использовать список понимания сделать два списка. Вы можете, конечно, использовать 'zip', чтобы перенести свой список кортежей в два списка, но зачем пытаться обучать коверу понимание списка здесь? Просто перебирайте свои кортежи и добавляйте к двум спискам ... держите это просто. –

+0

@ juanpa.arrivillaga: Я не знаю, согласен ли я с этим: в первую очередь понимание списков работает быстрее, чем добавление (в одном списке, действительно, при подаче двух списков он может быть менее эффективным). Кроме того, декларативный стиль использует не так много операций с побочными эффектами: у понимания списка обычно нет побочных эффектов: обычно пишется код, удобный для * читателей *, а не * писателей *. Кроме того, почему этот вопрос занижен? –

+0

@WillemVanOnsem Я не делал это вниз, для записи. Но, используя понимание, *, а затем * застегивая его, скорее всего, * не * будет быстрее, если только вы не используете понимание генератора, поэтому вы делаете это за один проход, а не сначала создавайте список кортежей в память. Но тогда, скорее всего, перенос цикла for в функцию, скорее всего, даст вам хорошую или лучшую производительность, чем использование генератора (что снижает производительность). Кроме того, это вопрос стиля и читаемости, но я думаю, что это субъективно. –

ответ

6

Прежде всего, вы сделали небольшую ошибку: она должна быть:

[f(value) for value in x] 
#^notice the `value` 

вместо:

[f(x) for value in x] 

Кроме того, дело в том, что:

return 2*x,x 

короток для:

return (2*x,x) 

так кортеж. Таким образом, ваше понимание списка генерирует список кортежей, а не набор строк. Хорошая вещь zip однако является то, что вы можете легко использовать его в обратном направлении звездочкой:

xlist,ylist = zip(*[f(value) for value in x]) 
#    ^with asterisk

Обратите внимание, что xlist и ylist будет кортежи (так zip будут распакованы).Если вы хотите, чтобы они были перечислены, вы можете использовать например:

xlist,ylist = map(list,zip(*[f(value) for value in x]))

, что приводит к:

>>> xlist 
[0, 2, 4] 
>>> ylist 
[0, 1, 4] 

(обратите внимание, что range s начинает отсчет от 0)

Альтернатива: Другим способом сделать это, конечно, является:

xlist = [f(value)[0] for value in x] 
ylist = [f(value)[1] for value in x] 

Но это, конечно, inelegantly и, кроме того, может быть неэффективным (данный f вычислительно дорог).

+1

Хороший звонок на редактирование, я генерировал простую версию и не тестировал простую версию, я обновляю приглашение. – Christophe

+1

Хороший улов на картинге тоже. В моем случае я повторяю возврат, поэтому списки или кортежи оба хороши, но это хорошо заметить. – Christophe

3

Использование

zip(*your_list_of_bituples) 

Пример

demo_list = [(1, 2), (2, 3), (4, 5)] 
zip(*demo_list) 

Даст

[(1, 2, 4), (2, 3, 5)] 
+0

Я даже не рассматривал zip (*), но это абсолютно правильный инструмент, и он решил мою проблему. Благодарим вас за быстрый ответ (я соглашусь через несколько минут, как только это разрешено). – Christophe

5

Используйте встроенный функция zip(),

def f(x): 
    return 2*x, x*x 

x = range(1, 4) 
xlist, ylist = zip(*[f(value) for value in x]) 

print(xlist, ylist) 
# ((2, 4, 6), (1, 4, 9)) 
5

Давайте сделаем эту работу. Эта функция отлично:

def f(x): 
    return 2*x, x*x 

Но вы хотите, чтобы определить диапазон следующим образом, обратите внимание на начальные и конечные значения:

x = range(1, 4) 

Кроме того, вы должны вызвать функцию со значением, а не с номером как параметр. И последний трюк, чтобы распаковать результат в двух списков, это просто zip(*lst) результат списка понимания:

xlist, ylist = zip(*[f(value) for value in x]) 

Теперь результат, как и ожидалось:

xlist 
=> [2, 4, 6] 
ylist 
=> [1, 4, 9]