2009-10-08 30 views
88

Mam listę, w której chcę zamienić wartości na Brak, gdzie condition() zwraca True.Zastępowanie wartości na liście przy użyciu Pythona

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

Na przykład, jeśli sprawdza stan bool (pozycja% 2) powinny powrócić:

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

Jaki jest najbardziej skuteczny sposób to zrobić?

+0

używać modułu itertools, jest najbardziej wydajny. – LtWorf

+1

W przypadku porównań "na miejscu" należy spojrzeć na to [odpowiedź] (http://stackoverflow.com/a/24203748/307454) – lifebalance

Odpowiedz

130

zbudować nową listę z wykazem zrozumieniem:

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

Można zmodyfikować oryginalne listy na miejscu, jeśli chcesz, ale nie faktycznie zaoszczędzić czas:

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 

Oto fragmenty (Python 3.6.3) demonstrujące nieczęstość czasu:

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) 

i Python 2.7.6 czasy:

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

czy to jest najbardziej wydajne? nie wylicza, że ​​musi utworzyć iterator i utworzyć krotkę, dodając narzut? są listami w listach kontrolnych Pythona, dając ci stały dostęp do czasu? – geowa4

+0

Myślę, i mogę się mylić, że miał na myśli kopię listy, która ma zostać zwrócona zamiast modyfikowania oryginału w miejscu. Ale nadal +1 za oferowanie wydajnego rozwiązania, gdy dozwolona jest modyfikacja na miejscu. –

+0

Jeśli chciałbym zmodyfikować oryginał w miejscu, czy nie byłoby również możliwe użycie narzędzia imap z 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

riffy na pytanie zadane przez boczną OP w komentarzu, a mianowicie:

co gdybym miał generator, który daje wartości z zakresu (11) zamiast z listy . Czy byłoby możliwe zastąpienie wartości w generatorze?

Jasne, że to banalnie proste ...:

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

Wystarczy przekazać dowolną iterable (w tym wyniku wywołania generator) jako pierwszy Arg, orzecznika zdecydować, czy wartość należy wymienić jako drugi argument i pozwól mu się zgrać.

Na przykład:

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

+1 hehe ... Chcę się nauczyć, jak napisać to" jedno "rozwiązanie dla fajnego Pythona ... hint pls – gath

+0

@gath, nie rozumiem twojego pytania - komentarze są dość ograniczone, więc powinieneś otworzyć nowe pytanie, abyś mógł rozwinąć i wyjaśnić, czego szukasz ... –

8

Oto kolejny sposób:

>>> 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 i jak faceci uczą się tego prostego kodu Pythona ... podpowiedzi – gath

+5

@gath: Don ' t dążyć do pisania jednolinijkowych do każdego celu. Czasami zwiększają czytelność lub wydajność, ale często nie. Co do podpowiedzi: Poznaj narzędzia używane przez Pythona, zwłaszcza listę (i dla Pythona 3 również), funkcje trójskładnikowego operatora, anonimowe (lambda) funkcje i funkcje, takie jak mapa, zip, filtrowanie, zmniejszanie itp. – balpha

2

To może pomóc ...

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

wyjaśnisz trochę, dlaczego uważasz, że może to pomóc? –

+0

@ T-Heron Można go zmodyfikować tak, aby spełniał zadane pytanie – Emil

+0

Jeśli ma być * zmodyfikowany *, to nie jest odpowiedzią na pytanie, które jest zadawane. Dokonaj niezbędnych zmian (lub wyjaśnij) lub usuń odpowiedź. –

0

W przypadku, gdy chcesz zastąpić wartości w miejscu, można zaktualizuj oryginalną listę wartościami z listy comprehensi włączone, przypisując całemu wycinkowi oryginału.

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 

Jeśli masz wiele nazw wskazujących na pierwotnej liście, np napisałeś data2=data przed zmianą listę i pominąć zapis plasterek na przypisanie data, data będzie ponownie powiązać się wskazywać na nowo utworzony lista podczas gdy data2 nadal wskazuje na niezmienioną listę oryginalną.

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] 

Uwaga: To nie jest rekomendacją dla generalnie preferują jedną nad drugą (zmiana listy na miejscu lub nie), ale zachowanie powinien być świadomy.

Powiązane problemy