2013-06-02 47 views
11

我對Python相當陌生,認爲這應該是一個相當普遍的問題,但找不到解決方案。我已經看過this page,發現它對一個項目很有幫助,但我很努力地將示例擴展到多個項目而不使用'for'循環。我正通過Emcee爲250名步行者運行這段代碼,所以我正在尋找可能的最快方式。創建單個列表項的列表乘以n次

我有號碼的清單,a = [x,y,z]我要重複b = [1,2,3]倍(例如),所以我結束了列表的列表:

[ 
[x], 
[y,y], 
[z,z,z] 
] 

的「for」循環我有是:

c = [ ] 
for i in range (0,len(a)): 
    c.append([a[i]]*b[i]) 

這正是我想要的,但意味着我的代碼極其慢。我也嘗試過天真地將a和b轉換爲數組,並且做着[a]*b,希望它能逐元素地增長,但沒有快樂。

回答

10

您可以使用zip和列表理解這裏:

>>> a = ['x','y','z'] 
>>> b = [1,2,3] 
>>> [[x]*y for x,y in zip(a,b)] 
[['x'], ['y', 'y'], ['z', 'z', 'z']] 

或:

>>> [[x for _ in xrange(y)] for x,y in zip(a,b)] 
[['x'], ['y', 'y'], ['z', 'z', 'z']] 

zip將首先在內存中創建整個列表,以獲得一個迭代器使用itertools.izip

如果a包含列表或列表列表等可變對象,則可能需要使用copy.deepcopy這裏是因爲改變一個副本會改變其他副本以及:

>>> from copy import deepcopy as dc 
>>> a = [[1 ,4],[2, 5],[3, 6, 9]] 
>>> f = [[dc(x) for _ in xrange(y)] for x,y in zip(a,b)] 

#now all objects are unique 
>>> [[id(z) for z in x] for x in f] 
[[172880236], [172880268, 172880364], [172880332, 172880492, 172880428]] 

timeit比較(忽略進口):

>>> a = ['x','y','z']*10**4 
>>> b = [100,200,300]*10**4 

>>> %timeit [[x]*y for x,y in zip(a,b)] 
1 loops, best of 3: 104 ms per loop 

>>> %timeit [[x]*y for x,y in izip(a,b)] 
1 loops, best of 3: 98.8 ms per loop 

>>> %timeit map(lambda v: [v[0]]*v[1], zip(a,b)) 
1 loops, best of 3: 114 ms per loop 

>>> %timeit map(list, map(repeat, a, b)) 
1 loops, best of 3: 192 ms per loop 

>>> %timeit map(list, imap(repeat, a, b)) 
1 loops, best of 3: 211 ms per loop 

>>> %timeit map(mul, [[x] for x in a], b) 
1 loops, best of 3: 107 ms per loop 

>>> %timeit [[x for _ in xrange(y)] for x,y in zip(a,b)] 
1 loops, best of 3: 645 ms per loop 

>>> %timeit [[x for _ in xrange(y)] for x,y in izip(a,b)] 
1 loops, best of 3: 680 ms per loop 
+1

我建議提一提'itertools.izip'。 – kirelagin

+1

謝謝!雖然'for'循環仍然會減慢代碼的速度嗎? – user2444731

+0

@ user2444731你是什麼意思「慢」?你爲什麼認爲''''循環慢?比較慢什麼? – kirelagin

1

這裏是沒有for環的版本,如果你不喜歡他們的某些原因:

map(lambda v: [v[0]]*v[1], zip(a,b)) 

我還要提醒你,這個版本比列表理解稍慢:

$ a = ['hi']*100 
$ b = [20]*100 

$ %timeit map(lambda v: [v[0]]*v[1], zip(a,b)) 
10000 loops, best of 3: 101 us per loop 

%timeit [[x]*y for x,y in zip(a,b)] 
10000 loops, best of 3: 74.1 us per loop 

我也建議使用itertools.izip代替zip如果你是Python的2

2

@kirelagin提出了一個版本,而不for環路,這裏是一個也沒有lambda S(請介意@AshwiniChaudhary溶液是最可讀的)

>>> from itertools import repeat 
>>> a = ['x','y','z'] 
>>> b = [1,2,3] 
>>> map(list, map(repeat, a, b)) 
[['x'], ['y', 'y'], ['z', 'z', 'z']] 

>>> map(repeat, a, b) 
[repeat('x', 1), repeat('y', 2), repeat('z', 3)] 

創建一個repeat對象的列表(在Python 2上使用imap。x如果你想要一個懶惰的迭代器而不是一個列表),它不佔用任何額外的內存空間,如果你只是想遍歷項目而不是存儲他們,這些都很好)

5

最快的方法它與map()operator.mul()

>>> from operator import mul 
>>> map(mul, [['x'], ['y'], ['z']], [1, 2, 3]) 
[['x'], ['y', 'y'], ['z', 'z', 'z']] 
+3

+1我剛剛發現它時發現它(輸入不是列表的列表) – jamylak

3
>>> from itertools import repeat 
>>> from itertools import starmap 
>>> a = ['x','y','z'] 
>>> b = [1,2,3] 
>>> starmap(repeat,zip(a,b)) 

starmap返回一個可迭代包含等於主叫repeat帶有參數等於包含在元組中的值,在這種情況下,例如('x',1)的結果值。

>>> for p in starmap(repeat,zip(a,b)): 
    print(list(p)) 


['x'] 
['y', 'y'] 
['z', 'z', 'z'] 
+0

請注意,您必須在'starmap'上調用'map(list,...)'到得到清單的列表 – jamylak