2017-02-21 49 views
4

我有一個函數返回兩個值,我想用列表理解來填充兩個列表。 例如:python列表理解多個返回函數

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個佔位符(元組列表)變量,以及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

注意xlistylist元組(因爲zip將解包)。如果你想他們是列表,可以例如使用:

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

導致:

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

(注意:range先從從0開始計數)

替代:另一種方法是:

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

但是這當然是不合理地並且此外可能是低效的(給定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]