2012-02-16 28 views
3

我有一個列表a,我想根據函數f更改元素a[i: j]。我能比天真的方式做得更好嗎?在for循環中修改列表元素

for index in range(i, j): 
    a[index] = f(a) 

[通過更好地我的意思是更接近於map(f, a),或者說更快。]

+0

你可能更喜歡''以上range' xrange'(見http://stackoverflow.com/a/135114/589206)。 – hochl 2012-02-16 03:21:12

+0

我認爲這更接近你的意圖:'對於索引,ai在枚舉(a [i:j],start = i): a [index] = f(ai)' – hughdbrown 2012-02-16 03:49:19

回答

3

您可以分配到切片:

a[i:j] = map(f, a[i:j]) 
+1

@Randomblue你試過了嗎? – 2012-02-16 12:52:54

+0

@Randomblue在片上閱讀。 http://docs.python.org/library/stdtypes.html#mutable-sequence-types「s [i:j] = t」從我到j的s片段被替換爲可迭代t的內容「 – hughdbrown 2012-02-16 13:26:59

1

使用列表理解...

a[i:j] = [f(ai) for ai in a[i:j]] 

map相當...

a[i:j] = map(f, a[i:j]) 
+0

這個時間有多好? – Randomblue 2012-02-16 01:46:06

+1

你應該在你的用例上進行測試。它可能取決於i和j的值以及元素的類型。 – 2012-02-16 01:48:24

2

我不打算做定時練習,但我會告訴你什麼內部代碼的各種選項變成。您的代碼是naive。切片爲l值的基於地圖的解決方案爲map_lvalue_slice。用切片作爲l值的列表理解是list_comp_lvalue_slice。相關列表理解一個解決方案使用一個元組,被稱爲tuple_lvalue_slice

>>> from dis import dis 
>>> 
>>> def naive(a, f, i, j): 
...  for index, ai in enumerate(a[i:j], start=i): 
...   a[index] = f(ai) 
... 
>>> def map_lvalue_slice(a, f, i, j): 
...  a[i:j] = map(f, a[i:j]) 
... 
>>> def list_comp_lvalue_slice(a, f, i, j): 
...  a[i:j] = [f(ai) for ai in a[i:j]] 
... 
>>> def tuple_lvalue_slice(a, f, i, j): 
...  a[i:j] = tuple(f(ai) for ai in a[i:j]) 
... 
>>> dis(naive) 
    2   0 SETUP_LOOP    55 (to 58) 
       3 LOAD_GLOBAL    0 (enumerate) 
       6 LOAD_FAST    0 (a) 
       9 LOAD_FAST    2 (i) 
      12 LOAD_FAST    3 (j) 
      15 SLICE+3    
      16 LOAD_CONST    1 ('start') 
      19 LOAD_FAST    2 (i) 
      22 CALL_FUNCTION   257 
      25 GET_ITER    
     >> 26 FOR_ITER    28 (to 57) 
      29 UNPACK_SEQUENCE   2 
      32 STORE_FAST    4 (index) 
      35 STORE_FAST    5 (ai) 

    3   38 LOAD_FAST    1 (f) 
      41 LOAD_FAST    5 (ai) 
      44 CALL_FUNCTION   1 
      47 LOAD_FAST    0 (a) 
      50 LOAD_FAST    4 (index) 
      53 STORE_SUBSCR   
      54 JUMP_ABSOLUTE   26 
     >> 57 POP_BLOCK   
     >> 58 LOAD_CONST    0 (None) 
      61 RETURN_VALUE   
>>> 
>>> dis(map_lvalue_slice) 
    2   0 LOAD_GLOBAL    0 (map) 
       3 LOAD_FAST    1 (f) 
       6 LOAD_FAST    0 (a) 
       9 LOAD_FAST    2 (i) 
      12 LOAD_FAST    3 (j) 
      15 SLICE+3    
      16 CALL_FUNCTION   2 
      19 LOAD_FAST    0 (a) 
      22 LOAD_FAST    2 (i) 
      25 LOAD_FAST    3 (j) 
      28 STORE_SLICE+3  
      29 LOAD_CONST    0 (None) 
      32 RETURN_VALUE   
>>> 
>>> dis(list_comp_lvalue_slice) 
    2   0 BUILD_LIST    0 
       3 LOAD_FAST    0 (a) 
       6 LOAD_FAST    2 (i) 
       9 LOAD_FAST    3 (j) 
      12 SLICE+3    
      13 GET_ITER    
     >> 14 FOR_ITER    18 (to 35) 
      17 STORE_FAST    4 (ai) 
      20 LOAD_FAST    1 (f) 
      23 LOAD_FAST    4 (ai) 
      26 CALL_FUNCTION   1 
      29 LIST_APPEND    2 
      32 JUMP_ABSOLUTE   14 
     >> 35 LOAD_FAST    0 (a) 
      38 LOAD_FAST    2 (i) 
      41 LOAD_FAST    3 (j) 
      44 STORE_SLICE+3  
      45 LOAD_CONST    0 (None) 
      48 RETURN_VALUE   
>>> 
>>> dis(tuple_lvalue_slice) 
    2   0 LOAD_GLOBAL    0 (tuple) 
       3 LOAD_CLOSURE    0 (f) 
       6 BUILD_TUPLE    1 
       9 LOAD_CONST    1 (<code object <genexpr> at 0xb748dc38, file "<stdin>", line 2>) 
      12 MAKE_CLOSURE    0 
      15 LOAD_FAST    0 (a) 
      18 LOAD_FAST    2 (i) 
      21 LOAD_FAST    3 (j) 
      24 SLICE+3    
      25 GET_ITER    
      26 CALL_FUNCTION   1 
      29 CALL_FUNCTION   1 
      32 LOAD_FAST    0 (a) 
      35 LOAD_FAST    2 (i) 
      38 LOAD_FAST    3 (j) 
      41 STORE_SLICE+3  
      42 LOAD_CONST    0 (None) 
      45 RETURN_VALUE   

的解決方案,解決最快的C代碼,最好是在一個緊密的循環,是最可取的在我的意見,因爲他們很可能大多采用優化C代碼,而不是主要解釋說明。我更喜歡切片作爲你的代碼的l值解決方案,我可能會傾向於地圖解決方案,儘管我主要是一名列表理解傢伙。

而且,這裏是證明他們是等價代碼:

>>> i, j = 4, 8 
>>> def f(ai): 
...  return -ai 
... 
>>> for fn in (naive, map_lvalue_slice, list_comp_lvalue_slice, tuple_lvalue_slice): 
...  a = range(10) 
...  fn(a, f, i, j) 
...  print "%-40s: %r" % (fn.__name__, a) 
... 
naive         : [0, 1, 2, 3, -4, -5, -6, -7, 8, 9] 
map_lvalue_slice      : [0, 1, 2, 3, -4, -5, -6, -7, 8, 9] 
list_comp_lvalue_slice     : [0, 1, 2, 3, -4, -5, -6, -7, 8, 9] 
tuple_lvalue_slice      : [0, 1, 2, 3, -4, -5, -6, -7, 8, 9]