2009-10-08 94 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] 

注:这是一般倾向于一个比其他 (到位变化列表或没有),但行为,你应该知道的任何建议。