2012-10-21 16 views
4

這是一個編程練習,而不是一個現實世界的問題:我在尋找一個類似於append行爲的生成器表達式。類似於追加行爲的生成器表達式

考慮:

def combine(sequence, obj): 
    for item in sequence: 
     yield item 
    yield obj 

s = ''.join(combine(sequence, obj)) 

該發電機基本上類似於append。在我的程序的工作流程上面是一樣快,

sequence.append(obj) 
s = ''.join(sequence) 

我現在想知道是否有一個整潔的發電機表達genexpr

s = ''.join(genexpr) 

類似於上述append行爲,而性能警告。

s = ''.join(_ for a in [sequence, [obj]] for _ in a) 

表現不好。

回答

4

使用chainitertools模塊嘗試:

''.join(chain(sequence, [obj])) 

如果你不想創建objlist,那麼,你可以嘗試這樣的:

''.join(chain(sequence, repeat(obj,1))) 

我會用[obj]作爲它更具可讀性,我懷疑repeat迭代器的開銷比list的創建更少。

+0

感謝。在我的代碼的上下文中,這兩個變體都與'sequence.append(obj); s =''.join(sequence)'。 –

+0

@ Jan-PhilipGehrcke'append'可能會導致列表擴展名(有時在剩餘可用空間添加新元素時,它會在幕後擴展)。雖然'chain'只創建遍歷現有元素的迭代器,所以不會有任何內存重新分配。 – ovgolovin

+0

@ Jan-PhilipGehrcke這就是我的意思:「將項目追加到列表所需的時間是」攤銷常量「;每當列表需要分配更多內存時,它會爲實際需要的多個項目分配空間,以避免在每次調用時重新分配(這假定內存分配器速度很快;對於大型列表,分配開銷可能會將行爲推向O(n * n))。「 (來自[這裏](http://effbot.org/zone/python-list.htm)) – ovgolovin

2

我不確定你的特定例子,但我發現使用+ [b]的速度與其他任何事物一樣快,即使是大列表。這裏是我的測試代碼:

import timeit 
from itertools import chain, repeat 

a=map(str,range(100000)) 
b='b' 

def combine(sequence,obj): 
    for item in sequence: 
    yield item 
    yield obj 

def test1(): 
    return ','.join(a+[b]) 

def test2(): 
    return ','.join(combine(a,b)) 

def test3(): 
    return ','.join(chain(a,repeat(b,1))) 

def test4(): 
    return ','.join(chain(a,[b])) 

def test5(): 
    return ','.join(y for x in [a,[b]] for y in x) 

count=100 
print 'test1: %g'%timeit.timeit(test1,number=count) 
print 'test2: %g'%timeit.timeit(test2,number=count) 
print 'test3: %g'%timeit.timeit(test3,number=count) 
print 'test4: %g'%timeit.timeit(test4,number=count) 
print 'test5: %g'%timeit.timeit(test5,number=count) 

這裏是我的系統上的結果:

test1: 0.475413 
test2: 0.977652 
test3: 0.550071 
test4: 0.548962 
test5: 0.968162 
+0

有趣的是,測試2和5在這裏顯示了相同的性能。是的,在我的代碼中使用'a + [b]'似乎很好。感謝您指出了這一點!現在,我不確定,你們哪一個贏得了綠色複選標記。你們兩人都提供了寶貴的見解。我們應該保持原樣嗎? :) –

+0

我認爲ovgolovin回答了你的實際問題。這是更多的FYI。 –