2009-10-08 98 views
88

我有一個列表,我想用None替換值,其中condition()返回True。使用Python替換列表中的值

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 

例如,如果條件檢查布爾(項%2)應返回:

[None, 1, None, 3, None, 5, None, 7, None, 9, None] 

什麼是最有效的方式做到這一點?

+0

使用itertools模塊,它是最高效的。 – LtWorf 2016-01-29 14:38:44

+1

對於'在-place'更換比較,看看這個【答案】(http://stackoverflow.com/a/24203748/307454) – lifebalance 2016-11-23 03:12:04

回答

130

建立與列表理解一個新的列表:

new_items = [x if x % 2 else None for x in items] 

您可以修改,地方,如果你想在原來的列表,但它實際上並沒有節省時間:

items = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 
for index, item in enumerate(items): 
    if not (item % 2): 
     items[index] = None 

下面是(Python 3.6.3)演示非時隙的時序:

In [1]: %%timeit 
    ...: items = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 
    ...: for index, item in enumerate(items): 
    ...:  if not (item % 2): 
    ...:   items[index] = None 
    ...: 
1.06 µs ± 33.7 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each) 

In [2]: %%timeit 
    ...: items = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 
    ...: new_items = [x if x % 2 else None for x in items] 
    ...: 
891 ns ± 13.6 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each) 

和Python 2.7.6計時:

In [1]: %%timeit 
    ...: items = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 
    ...: for index, item in enumerate(items): 
    ...:  if not (item % 2): 
    ...:   items[index] = None 
    ...: 
1000000 loops, best of 3: 1.27 µs per loop 
In [2]: %%timeit 
    ...: items = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 
    ...: new_items = [x if x % 2 else None for x in items] 
    ...: 
1000000 loops, best of 3: 1.14 µs per loop 
+2

是最有效的?不枚舉必須創建一個迭代器並形成一個元組,增加開銷? Python列表列表中的列表,給你不斷的時間訪問? – geowa4 2009-10-08 20:05:26

+0

我想,我可能是錯的,他的意思是要返回列表的副本,而不是修改原來的位置。但是,當允許就地修改時提供有效的解決方案仍然+1。 – 2009-10-08 20:07:07

+0

如果我想修改原始位置,是不是也可以使用itertools中的imap? – 2009-10-08 20:19:44

2
>>> L = range (11) 
>>> [ x if x%2 == 1 else None for x in L ] 
[None, 1, None, 3, None, 5, None, 7, None, 9, None] 
53
ls = [x if (condition) else None for x in ls] 
10

Riffing上側的問題由OP在評論問,即:

如果我有一臺發電機能產生 值範圍(11)而不是 列表。是否可以取代發生器中的 值?

當然,這是很輕鬆...:

def replaceiniter(it, predicate, replacement=None): 
    for item in it: 
    if predicate(item): yield replacement 
    else: yield item 

只是通過可迭代的(包括調用生成的結果)作爲第一個參數,謂詞來決定是否值必須更換作爲第二個參考,讓我們呃裂口。

例如:

>>> list(replaceiniter(xrange(11), lambda x: x%2)) 
[0, None, 2, None, 4, None, 6, None, 8, None, 10] 
+0

+1呵呵......我想學習如何寫這個‘一’行漂亮的蟒蛇解決方案...提示請 – gath 2009-10-09 11:34:37

+0

@gath,我不明白你的問題 - 評論是漂亮的限制,所以你應該打開一個新的問題,所以你可以展開和闡明你要找的是它... – 2009-10-09 15:23:55

8

這裏的另一種方式:

>>> L = range (11) 
>>> map(lambda x: x if x%2 else None, L) 
[None, 1, None, 3, None, 5, None, 7, None, 9, None] 
+1

+1以及如何傢伙學這一行漂亮的Python代碼...提示 – gath 2009-10-09 11:33:24

+5

@gath:唐」不希望爲每一個目的寫一行。有時,他們會增加可讀性或性能,但通常不會。至於提示:瞭解的工具了Python ofters,特別是列表(和Python 3也有字典)解析,三元運算符,匿名(拉姆達)功能,以及像地圖,壓縮,過濾功能,減少等 – balpha 2009-10-09 12:56:02

2

這可能有助於...

test_list = [5, 8] 
test_list[0] = None 
print test_list 
#prints [None, 8] 
+1

燦你解釋一下你爲什麼認爲這可能有幫助? – 2017-01-14 00:48:09

+0

@ T-Heron它可以被修改以滿足問題的要求 – Emil 2017-01-15 23:24:48

+0

如果它需要*修改*,那麼它不是被問到的問題的答案。請自己作出(或解釋)必要的修改,或刪除答案。 – 2017-08-02 09:55:57

0

如果你要到位,以取代值,可以 用列表中的值更新您的原始列表 comprehensi通過分配原稿的整個片段。

data = [*range(11)] # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 
id_before = id(data) 
data[:] = [x if x % 2 else None for x in data] 
data 
# Out: [None, 1, None, 3, None, 5, None, 7, None, 9, None] 
id_before == id(data) # check if list is still the same 
# Out: True 

如果你有指向原來的列表中的多個名稱, 比如你改變列表 以前寫data2=data,你跳過切片標誌分配到datadata將重新綁定到指向新創建而data2仍指向原來的不變清單。

data = [*range(11)] # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 
data2 = data 
id_before = id(data) 
data = [x if x % 2 else None for x in data] # no [:] here 
data 
# Out: [None, 1, None, 3, None, 5, None, 7, None, 9, None] 
id_before == id(data) # check if list is still the same 
# Out: False 
data2 
# Out: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 

注:這是一般傾向於一個比其他 (到位變化列表或沒有),但行爲,你應該知道的任何建議。