2009-10-08 2 views
88

У меня есть список, где я хочу заменить значения None, где condition() возвращает True.Заменить значения в списке с помощью Python

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

Например, если условие проверяет BOOL (пункт 2%) должен возвращать:

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

Что является наиболее эффективным способом сделать это?

+0

использовать модуль itertools, это самый эффективный. – LtWorf

+1

Для сравнения с заменой «на месте» ознакомьтесь с этим [ответом] (http://stackoverflow.com/a/24203748/307454) – lifebalance

ответ

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 arraylists, дающие вам постоянный доступ к времени? – geowa4

+0

Я думаю, и я могу ошибаться, что он предназначался для копии списка, который нужно вернуть, вместо того, чтобы модифицировать оригинал. Но тем не менее, +1 для обеспечения эффективного решения, когда допускается модификация на месте. –

+0

Если бы я хотел изменить оригинал на месте, не могли бы также использовать imap из itertools? –

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

риффов на стороне вопрос, заданный ОП в комментарии, а именно:

, что если бы я был генератор, который дает значения из диапазона (11) вместо списка . Можно ли заменить значения в генераторе?

Конечно, это тривиально просто ...:

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

Просто пройти любой итерацию (в том числе в результате вызова генератора) в качестве первого арг, предикат, чтобы решить, если значение должно быть заменено как второй аргумент, и пусть «er rip».

Например:

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

+1 хе-хе ... я хочу узнать, как написать эту« одну »линию отличного решения python ... hint pls – gath

+0

@gath, я не понимаю ваш вопрос - комментарии довольно ограничивая, поэтому вы должны открыть новый вопрос, чтобы вы могли расширить и уточнить, что вы ищете ... –

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

+5

@gath: Don ' t стремятся писать однострочные для каждой цели. Иногда они повышают читаемость или производительность, но часто они этого не делают. Что касается подсказок: ознакомьтесь с инструментами, которые Python ofters, особенно для списков (и для Python 3 также dict), тернарный оператор, анонимные функции (lambda) и функции, такие как map, zip, filter, reduce и т. Д. – balpha

2

Это может помочь ...

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

Can вы объясните, почему вы думаете, что это может помочь? –

+0

@ T-Heron Он может быть изменен, чтобы выполнить то, что задает вопрос – Emil

+0

Если это необходимо * изменить *, то это не ответ на заданный вопрос. Пожалуйста, либо сделайте (или объясните) необходимые изменения самостоятельно, либо удалите ответ. –

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 перед изменением списка и пропустить срезо обозначения для присвоения data, data будет перепривязывает, чтобы указать на вновь созданный а 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] 

Примечание: Это не рекомендация, как правило, предпочитая один над другим (изменение списка на месте или нет), но поведение, которое вы должны быть в курсе.

Смежные вопросы