2016-07-30 27 views
0

我想填充三個列表列出清單相結合。即,f返回stuff_for_A,stuff_for_B,stuff_for_C其中每個stuff是包含N個項目的列表。我想加入每個到他們各自的列表,因爲我循環迭代發送輸入到f從函數返回應用列表解析

如何編寫超快速列表理解來創建這3個列表?

注意:如果能讓事情變得更簡單,我可以重構f的輸出(例如將項目拉到一起)。

編輯:這是一些底部列表理解不正確的僞代碼。

def f(input): 
    x = precompute(input) 
    stuff_for_A = create_A_list(x) 
    stuff_for_B = create_B_list(x) 
    stuff_for_C = create_C_list(x) 
    return stuff_for_A,stuff_for_B,stuff_for_C 
A,B,C = [f(input) for input in iterable] 
+1

你questio懶n在語法上是清晰的,但是沒有看到一些代碼或僞代碼,你無法準確理解你想要做什麼。 –

+0

你可以添加你的代碼嗎?至於函數'f',它是否返回一個將每個列表映射到其相關對象的字典? – kaveh

+0

增加了一些僞代碼。 f目前不返回字典,應該嗎? – cgreen

回答

0

直接擴展A,B,C而不返回東西?

iterable = range(10) 
A, B, C = [], [], [] 

def f(item): 
    A.extend([item * 2]) 
    B.extend([item * 3]) 
    C.extend([item * 4]) 

map(f, iterable) 
print A 
print B 
print C 

https://repl.it/Chl6

(我用.extend()裏面列出,因爲你的函數返回列表,否則使用A.add(thing)添加個性的東西。我也改名爲inputitem因爲input()是Python中的內置函數)

+0

儘量不要使用'map'來代替'f'的副作用;它會創建一個立即丟棄的列表(在這種情況下爲'None'值)。只需使用'for'循環:'對於我在iterable:f(i)'中。 – chepner

1

看來,你想要的結果相同

A = [create_A_list(input) for input in iterable] 
B = [create_B_list(input) for input in iterable] 
C = [create_C_list(input) for input in iterable] 

但只有一個通過iterable。有了明確的for循環,你會用

A = [] 
B = [] 
C = [] 
for input in iterable: 
    A.append(create_A_input(input)) 
    B.append(create_B_input(input)) 
    C.append(create_C_input(input)) 

與一個列表理解,你可以得到三倍的列表:

triples = [ (create_A_input(input), 
      create_B_input(input), 
      create_C_input(input)) for input in iterable ] 

然後你可以轉成三重名單:

A, B, C = map(list, zip(*[(create_A_input(input), 
          create_B_input(input), 
          create_C_input(input)) for input in iterable])) 

你原來f函數返回一個三重,所以你可以使用使用到位三聯的在前面:

A, B, C = map(list, zip(*[f(input) for input in iterable)])) 
+0

非常清楚。一個問題:你會期望這裏的列表理解比明確的for循環更快嗎?有一些生成器表達式而不是(createA(),createB(),createC())會更好嗎?我不確定在什麼情況下理解速度更快,一般來說,這可能是另一個問題...... – cgreen

+0

我懷疑顯式循環和列表理解之間的速度差別不大。基於生成器的解決方案可能*比'zip(* [...])'慢,但視覺上更清晰;生成器針對內存使用進行了優化,而不是執行速度。 – chepner

+0

'A,B,C = zip([f(x)for f in(create_A_input,create_B_input,create_C_input)] for iterable]'應該也可以。 – chepner

1

要創建列表從返回元組,你可以使用與zip在發電機表達拆包多個任務:

def f(input): 
    ... 
    return stuff_for_A,stuff_for_B,stuff_for_C 

A, B, C = zip(*(f(input) for input in iterable)) 

這將返回各自的項目每個列表分組爲3元組。


試用:

>>> A, B, C = zip(*[(1,2,3), (4,5,6), ('x', 'y', 'z'), (8,9,0)]) 
>>> A 
(1, 4, 'x', 8) 
>>> B 
(2, 5, 'y', 9) 
>>> C 
(3, 6, 'z', 0) 

要返回他們的名單,而不是,您可以使用列表理解與以前的操作:

>>> A, B, C = [list(i) for i in zip(*[(1,2,3), (4,5,6), ('x', 'y', 'z'), (8,9,0)])] 
>>> A 
[1, 4, 'x', 8] 
>>> B 
[2, 5, 'y', 9] 
>>> C 
[3, 6, 'z', 0] 

在該函數返回一個tup 3個iterables樂,那麼你可以使用itertools.chainzip扁平化的結果:

from itertools import chain 

A, B, C = (list(chain.from_iterable(i)) 
      for i in zip(*(f(input) 
          for input in iterable))) 
+0

問題:在你的試驗中,你沒有測試正確的東西。輸出一個列表列表,比如說'[A1,A2,A3],[B1,B2,B3],[C1,C2,C3]',用於'iterable'中的每個列表。我想將所有的As在所有迭代中,所以我最終得到三個列表'[A1,A2,A3,A4,A5,...]','[B1,B2,B3,B4,B5 ...]等 – cgreen

+0

@cgreen You可以使用'chain'將列表弄平如我所做的那樣,但是你可能會考慮重寫該函數,例如改變'A,B,C'而不是:) –

+0

對不起,你會從'f'返回什麼,不得不使用'鏈'? – cgreen

1

如果ABC存在,下面就與返回的值更新他們f

list(map(lambda x: x[0].extend(x[1]), zip([A,B,C], f())))

list叫,原因map在Python 3

+0

不確定'zip([A,B,C],f())'是否與括號不匹配? – cgreen

+0

來自文檔:「Zip使迭代器聚合來自每個迭代器的元素」。在這裏它返回一個匹配每個列表的元組到它由'f'返回的相關數據,然後'map'應用'extend'函數https:// docs。python.org/3/library/functions.html#zip – kaveh