2013-01-16 43 views
7

我有一個列表:mylist = [0, 0, 0, 0, 0]更換出現選擇列表中的元素在Python

我只希望替換選擇的元素,比方說第一,第二,和一個共同的數量,A = 100第四。要做到這一點

方式一:

mylist[:2] = [A]*2 
mylist[3] = A 
mylist 
[100, 100, 0, 100, 0] 

我要尋找一個班輪,或者更簡單的方法來做到這一點。更普遍和靈活的答案是可取的。

+0

這個怎麼樣? mylist [:2],mylist [3] = [A] * 2,A –

回答

7

特別是因爲您要更換的一個相當大的塊list,我會做這個不可改變:

mylist = [100 if i in (0, 1, 3) else e for i, e in enumerate(mylist)] 

這是故意在Python這使得新list是一個班輪,而變異的一個list需要一個顯式循環。通常,如果你不知道你想要哪一個,你需要新的list。 (在某些情況下,它更慢或更復雜,或者你有一些其他代碼引用了相同的list,並需要看到它發生了變異,或者其他,這就是爲什麼這是「通常」而不是「始終」。)

如果你想要做一次這樣多,我包起來的功能,如波動說明:

def elements_replaced(lst, new_element, indices): 
    return [new_element if i in indices else e for i, e in enumerate(lst)] 

我個人很可能會使其成爲一個發電機,因此產生一個迭代的,而不是返回一個列表,即使我永遠不會需要這個,只是因爲我這樣愚蠢。但是,如果你真的需要它:

myiter = (100 if i in (0, 1, 3) else e for i, e in enumerate(mylist)) 

或者:

def elements_replaced(lst, new_element, indices): 
    for i, e in enumerate(lst): 
     if i in indices: 
      yield new_element 
     else: 
      yield e 
+0

關於新列表和變異的好解釋。 – elwc

+0

有時我會錯過'valarray :: gslice' – Abhijit

+0

@Abhijit:幾乎所有的情況下,'valarray'在C++中都是有意義的,'numpy'在Python中是有意義的,'numpy'的擴展切片比幾乎所有情況下都有'gslice'。例如,請參閱mgilson對此問題的回答。 (當然,「幾乎所有」和「幾乎所有」與「every」和「all」並不完全相同......但是我很少發現自己正在編寫一些'numpy'代碼並且缺少C++功能......) – abarnert

0

這是你在找什麼?列出要更改的索引,然後遍歷該列表以更改值。

els_to_replace = [0, 1, 3] 

mylist = [0, 0, 0, 0, 0] 

for index in els_to_replace: 
    mylist[index] = 100 


mylist 
Out[9]: [100, 100, 0, 100, 0] 
2
def replace_element(lst, new_element, indices): 
    for i in indices: 
     lst[i] = new_element 
    return lst 

這絕對是一個更通用的解決方案,而不是一個班輪雖然。例如,你的情況,你會打電話:

mylist = replace_element(mylist, 100, [0, 1, 3]) 
+0

+1。除了更普遍之外,我認爲這是做可變替換的最可讀的方式,儘管(或者可能是因爲)不是單線程的。 – abarnert

1

numpy的支持這一點,如果你不反對使用np.ndarray

>>> a = np.zeros(5) 
>>> a[[0,1,3]] = 100 
>>> a 
array([ 100., 100., 0., 100., 0.]) 
+0

+1。即使這並不直接回答OP的問題(我不確定它沒有),但是每當你發現自己處理數字序列並且看起來比應該更難時,你應該問的第一個問題可能是「我是否反對在這裏使用'np.ndarray'?」 – abarnert

0

不是這一個巨大的風扇,但你可以試試這個(雖然我覺得所有上述得多簡潔易讀):從可疑的可讀性

In [22]: from operator import setitem 

In [23]: mylist = [0, 0, 0, 0, 0] 

In [24]: indeces_to_replace = [0, 1, 3] 

In [25]: _ = map(lambda x: setitem(mylist, x, 100), indeces_to_replace) 

In [26]: mylist 
Out[26]: [100, 100, 0, 100, 0] 

一邊,需要進口,@abarnert指出了一些額外的問題,即map仍會創建一個不必要的列表(該列表會被_丟棄,但會被創建),並且它不能在Python 3中工作,因爲Python 3.x中的mapreturns an iterator。您可以使用six模塊來模擬Python 2中Python 3.x中map的行爲。x以及與collections.deque(再次按照@abarnert的建議)結合使用時,可以在不創建內存中的附加列表的情況下實現相同的輸出,因爲可包含最多0項目將放棄從迭代器map收到的所有內容(注意six,map通過使用itertools.imap來模擬)。

同樣,也完全沒有必要永遠使用這個 - 高於/低於每一個解決方案是更好:)

In [1]: from collections import deque 

In [2]: from six.moves import map 

In [3]: from operator import setitem 

In [4]: mylist = [0, 0, 0, 0, 0] 

In [5]: indeces_to_replace = [0, 1, 3] 

In [6]: deque(map(lambda x: setitem(mylist, x, 100), indeces_to_replace), maxlen=0) 
Out[6]: deque([], maxlen=0) 

In [7]: mylist 
Out[7]: [100, 100, 0, 100, 0] 
+0

主要與此相關的問題是,在Python 3中,它不起作用,因爲您只需取回一個永遠不會迭代的迭代器。較小的問題是,在Python 2中,它構建了一個你不需要的列表。你可以通過明確地執行list(map(...))來解決第一個問題。或者你可以通過使用'six.map'並將結果傳遞給一個'iter_discard'函數來解決這兩個問題,你可以將它作爲'collections.deque(it,max_size = 0)'來實現。這是一個更多的想法,你應該把它放在一個解決方案,你不是一個巨大的粉絲,當然... – abarnert

+0

@abarnert遲到+1到你的答案(一如既往的信息),和偉大的觀點關於這個實現(從未考慮過將'map'的結果傳遞給'iter_discard'函數)。我會爲後人的緣故添加一個更新,並且一如既往地感謝有用的信息:) – RocketDonkey

+0

我真的希望'iter_discard'是3.x標準庫的一部分。反對它的觀點是,這將鼓勵人們使用'map'來代替結果(而且,如果你真的想要,'deque'技巧已經被添加到'itertools'文檔的某處)。我可以買那個......但是對於這些問題,人們總是這樣做(然後想用他們可以找到的每個Python版本來「計時」結果)。 – abarnert

0

我喜歡列表理解:

[100 if index in [1, 4] else 0 for index, x in enumerate(mylist) ]