Ich habe eine Liste, in der ich Werte durch Keine ersetzen möchte, wobei condition () True zurückgibt.
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Wenn Bedingungsprüfungen bool (Element% 2) beispielsweise zurückgegeben werden sollen:
[None, 1, None, 3, None, 5, None, 7, None, 9, None]
Was ist der effizienteste Weg, dies zu tun?
Erstellen Sie eine neue Liste mit einem Listenverständnis:
new_items = [x if x % 2 else None for x in items]
Sie können die ursprüngliche Liste vor Ort ändern, wenn Sie möchten, es spart jedoch keine Zeit:
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
Hier sind (Python 3.6.3) Timings, die die Nicht-Zeitspeicherung demonstrieren:
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)
Und Python 2.7.6-Timings:
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
ls = [x if (condition) else None for x in ls]
Riffing auf eine vom OP in einem Kommentar gestellte Nebenfrage, d. H .:
was wäre, wenn ich einen Generator hätte, der ergibt die Werte aus Bereich (11) anstelle von Liste. Wäre es möglich, .__ zu ersetzen. Werte im Generator?
Sicher, es ist trivial einfach ...:
def replaceiniter(it, predicate, replacement=None):
for item in it:
if predicate(item): yield replacement
else: yield item
Übergeben Sie einfach jedes iterierbare Element (einschließlich des Ergebnisses des Aufrufs eines Generators) als erstes Argument, das Prädikat, um zu entscheiden, ob ein Wert als zweites Argument ersetzt werden muss, und lassen Sie ihn rippen.
Zum Beispiel:
>>> list(replaceiniter(xrange(11), lambda x: x%2))
[0, None, 2, None, 4, None, 6, None, 8, None, 10]
Hier ist ein anderer Weg:
>>> L = range (11)
>>> map(lambda x: x if x%2 else None, L)
[None, 1, None, 3, None, 5, None, 7, None, 9, None]
>>> 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]
Wenn Sie vorhandene Werte ersetzen möchten, können Sie Ihre ursprüngliche Liste durch Werte aus einem Listenverständnis aktualisieren, indem Sie dem gesamten Teil des Originals zuweisen.
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
Wenn Sie mehrere Namen haben, die auf die ursprüngliche Liste verweisen, haben Sie beispielsweise data2=data
bevor Sie die Liste ändern und die Slice-Notation für die Zuweisung zu data
überspringen, wird data
erneut gebunden, um auf die neu erstellte Liste zu zeigen, während data2
zeigt immer noch auf die ursprüngliche unveränderte Liste.
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]
Hinweis: Dies ist keine Empfehlung für den generellen Vorzug vor der anderen (Änderung der Liste oder nicht), aber Verhalten, das Sie kennen sollten.