it-swarm.com.de

Mehrere Elemente aus einer Liste löschen

Ist es möglich, mehrere Elemente gleichzeitig aus einer Liste zu löschen? Wenn ich Elemente am Index 0 und 2 löschen und etwas wie del somelist [0] gefolgt von del somelist [2] versuchen möchte, löscht die zweite Anweisung tatsächlich somelist [3].

Ich nehme an, ich könnte immer zuerst die höher nummerierten Elemente löschen, aber ich hoffe, dass es einen besseren Weg gibt.

138
Joe Calimari

Wahrscheinlich nicht die beste Lösung für dieses Problem:

indices = 0, 2
somelist = [i for j, i in enumerate(somelist) if j not in indices]
96
SilentGhost

Aus irgendeinem Grund mag ich keine der Antworten hier. Ja, sie funktionieren, aber genau genommen löschen die meisten von ihnen keine Elemente in einer Liste, oder? (Erstellen Sie jedoch eine Kopie, und ersetzen Sie dann das Original durch die bearbeitete Kopie.).

Warum nicht einfach zuerst den höheren Index löschen?

Gibt es einen Grund dafür? Ich würde einfach tun:

for i in sorted(indices, reverse=True):
    del somelist[i]

Wenn Sie Elemente wirklich nicht rückwärts löschen möchten, sollten Sie einfach die Indexwerte inkrementieren, die größer sind als der zuletzt gelöschte Index (kann nicht wirklich den gleichen Index verwenden, da Sie eine andere Liste haben) oder verwenden eine Kopie der Liste (die nicht "löschen", sondern das Original durch eine bearbeitete Kopie ersetzen würde).

Fehlt mir hier etwas, irgendeinen Grund, NICHT in umgekehrter Reihenfolge zu löschen?

141
tglaria

Wenn Sie mehrere nicht benachbarte Elemente löschen, ist das, was Sie beschreiben, der beste Weg (und ja, beginnen Sie mit dem höchsten Index).

Wenn Ihre Elemente benachbart sind, können Sie die Slice-Zuweisungssyntax verwenden:

a[2:10] = []
101
Greg Hewgill

Als eine Funktion:

def multi_delete(list_, *args):
    indexes = sorted(list(args), reverse=True)
    for index in indexes:
        del list_[index]
    return list_

Läuft in n log (n) Zeit, was es zur schnellsten korrekten Lösung machen sollte.

18
Nikhil Chelliah

Als Spezialisierung von Gregs Antwort können Sie sogar die erweiterte Slice-Syntax verwenden. z.B. Wenn Sie die Punkte 0 und 2 löschen wollten:

>>> a= [0, 1, 2, 3, 4]
>>> del a[0:3:2]
>>> a
[1, 3, 4]

Dies deckt natürlich keine willkürliche Auswahl ab, kann aber durchaus zum Löschen von zwei Elementen verwendet werden.

17
bobince

Sie können numpy.delete Wie folgt verwenden:

import numpy as np
a = ['a', 'l', 3.14, 42, 'u']
I = [0, 2]
np.delete(a, I).tolist()
# Returns: ['l', '42', 'u']

Wenn es Ihnen nichts ausmacht, am Ende ein numpy - Array zu erhalten, können Sie die .tolist() weglassen. Sie sollten auch einige größere Geschwindigkeitsverbesserungen feststellen, die diese Lösung skalierbarer machen. Ich habe es nicht verglichen, aber numpy Operationen sind kompilierter Code, der entweder in C oder Fortran geschrieben wurde.

17
philE

Sie möchten also im Wesentlichen mehrere Elemente in einem Durchgang löschen? In diesem Fall wird die Position des nächsten zu löschenden Elements um die Anzahl der zuvor gelöschten Elemente verschoben.

Unser Ziel ist es, alle Vokale zu löschen, die als Indizes 1, 4 und 7 vorberechnet wurden. Beachten Sie, dass die Indizes to_delete in aufsteigender Reihenfolge vorliegen, da sie sonst nicht funktionieren.

to_delete = [1, 4, 7]
target = list("hello world")
for offset, index in enumerate(to_delete):
  index -= offset
  del target[index]

Komplizierter wäre es, wenn Sie die Elemente in beliebiger Reihenfolge löschen möchten. IMO, Sortierung to_delete ist möglicherweise einfacher, als herauszufinden, wann Sie von index subtrahieren sollten oder nicht.

11

Ich bin ein absoluter Anfänger in Python, und meine Programmierung ist im Moment, gelinde gesagt, grob und dreckig, aber meine Lösung bestand darin, eine Kombination der grundlegenden Befehle zu verwenden, die ich in früheren Tutorials gelernt habe:

SomeList = [1,2,3,4,5,6,7,8,10]
Rem = [0,5,7]

for i in Rem:
    SomeList[i]='!' # mark for deletion

for i in range(0,SomeList.count('!')):
    SomeList.remove('!') # remove
print SomeList

Da ein Zeichen zum Löschen ausgewählt werden muss, hat dies natürlich seine Grenzen.

Was die Leistung im Verhältnis zur Größe der Liste betrifft, bin ich mir sicher, dass meine Lösung nicht optimal ist. Es ist jedoch unkompliziert, was hoffentlich andere Anfänger anspricht und in einfachen Fällen funktioniert, in denen SomeList ein bekanntes Format hat, z. B. immer numerisch ...

6
Paul

Hier ist eine Alternative, die zum Erstellen von Tupeln nicht enumerate () verwendet (wie in der ursprünglichen Antwort von SilentGhost).

Das scheint mir lesbarer zu sein. (Vielleicht würde ich mich anders fühlen, wenn ich es gewohnt wäre, Aufzählen zu verwenden.) CAVEAT: Ich habe die Leistung der beiden Ansätze nicht getestet.

# Returns a new list. "lst" is not modified.
def delete_by_indices(lst, indices):
    indices_as_set = set(indices)
    return [ lst[i] for i in xrange(len(lst)) if i not in indices_as_set ]

HINWEIS: Python 2.7-Syntax. Für Python 3, xrange => range.

Verwendung:

lst = [ 11*x for x in xrange(10) ]
somelist = delete_by_indices( lst, [0, 4, 5])

somelist:

[11, 22, 33, 66, 77, 88, 99]

--- BONUS ---

Löschen Sie mehrere Werte aus einer Liste. Das heißt, wir haben die Werte, die wir löschen möchten:

# Returns a new list. "lst" is not modified.
def delete__by_values(lst, values):
    values_as_set = set(values)
    return [ x for x in lst if x not in values_as_set ]

Verwendung:

somelist = delete__by_values( lst, [0, 44, 55] )

somelist:

[11, 22, 33, 66, 77, 88, 99]

Dies ist die gleiche Antwort wie zuvor, aber diesmal haben wir die zu löschenden WERTE angegeben [0, 44, 55].

5
ToolmakerSteve

Eine alternative Listenverständnismethode, die Listenindexwerte verwendet:

stuff = ['a', 'b', 'c', 'd', 'e', 'f', 'woof']
index = [0, 3, 6]
new = [i for i in stuff if stuff.index(i) not in index]

Dies ergibt:

['b', 'c', 'e', 'f']
4
Meow

hier ist eine andere Methode, mit der die Elemente entfernt werden. Auch wenn Ihre Liste sehr lang ist, ist sie schneller.

>>> a = range(10)
>>> remove = [0,4,5]
>>> from collections import deque
>>> deque((list.pop(a, i) for i in sorted(remove, reverse=True)), maxlen=0)

>>> timeit.timeit('[i for j, i in enumerate(a) if j not in remove]', setup='import random;remove=[random.randrange(100000) for i in range(100)]; a = range(100000)', number=1)
0.1704120635986328

>>> timeit.timeit('deque((list.pop(a, i) for i in sorted(remove, reverse=True)), maxlen=0)', setup='from collections import deque;import random;remove=[random.randrange(100000) for i in range(100)]; a = range(100000)', number=1)
0.004853963851928711
4
user545424
l = ['a','b','a','c','a','d']
to_remove = [1, 3]
[l[i] for i in range(0, len(l)) if i not in to_remove])

Es ist im Grunde das Gleiche wie die Antwort mit den meisten Stimmen, nur eine andere Art, sie zu schreiben. Beachten Sie, dass die Verwendung von l.index () keine gute Idee ist, da damit keine doppelten Elemente in einer Liste verarbeitet werden können.

3
zinc

Dies wurde erwähnt, aber irgendwie hat es niemand geschafft, es richtig zu machen.

Bei O(n) wäre die Lösung:

indices = {0, 2}
somelist = [i for j, i in enumerate(somelist) if j not in indices]

Dies kommt der Version von SilentGhost sehr nahe, fügt jedoch zwei geschweifte Klammern hinzu.

3
Veedrac

Ich wollte die verschiedenen Lösungen vergleichen, die es einfach machten, die Knöpfe zu drehen.

Zuerst habe ich meine Daten generiert:

import random

N = 16 * 1024
x = range(N)
random.shuffle(x)
y = random.sample(range(N), N / 10)

Dann habe ich meine Funktionen definiert:

def list_set(value_list, index_list):
    index_list = set(index_list)
    result = [value for index, value in enumerate(value_list) if index not in index_list]
    return result

def list_del(value_list, index_list):
    for index in sorted(index_list, reverse=True):
        del(value_list[index])

def list_pop(value_list, index_list):
    for index in sorted(index_list, reverse=True):
        value_list.pop(index)

Dann habe ich timeit verwendet, um die Lösungen zu vergleichen:

import timeit
from collections import OrderedDict

M = 1000
setup = 'from __main__ import x, y, list_set, list_del, list_pop'
statement_dict = OrderedDict([
    ('overhead',  'a = x[:]'),
    ('set', 'a = x[:]; list_set(a, y)'),
    ('del', 'a = x[:]; list_del(a, y)'),
    ('pop', 'a = x[:]; list_pop(a, y)'),
])

overhead = None
result_dict = OrderedDict()
for name, statement in statement_dict.iteritems():
    result = timeit.timeit(statement, number=M, setup=setup)
    if overhead is None:
        overhead = result
    else:
        result = result - overhead
        result_dict[name] = result

for name, result in result_dict.iteritems():
    print "%s = %7.3f" % (name, result)

Ausgabe

set =   1.711
del =   3.450
pop =   3.618

Der Generator mit den Indizes in set war also der Gewinner. Und del ist etwas schneller als pop.

2
David Cullen

Mit der Methode Remove werden viele Listenelemente verschoben. Ich denke, es ist besser, eine Kopie zu machen:

...
new_list = []
for el in obj.my_list:
   if condition_is_true(el):
      new_list.append(el)
del obj.my_list
obj.my_list = new_list
...
2
luca

verwenden Sie dazu eine for-Schleife, die die Indizes durchläuft, nachdem Sie die Indexliste in absteigender Reihenfolge sortiert haben

mylist=[66.25, 333, 1, 4, 6, 7, 8, 56, 8769, 65]
indexes = 4,6
indexes = sorted(indexes, reverse=True)
for i in index:
    mylist.pop(i)
print mylist
2
Gourav Singla

technisch gesehen lautet die Antwort NEIN. Es ist nicht möglich, zwei Objekte AT GLEICHZEITIG zu löschen. Es ist jedoch IS möglich, zwei Objekte in einer Zeile schönen Pythons zu löschen.

del (foo['bar'],foo['baz'])

löscht wiederkehrend foo['bar'], dann foo['baz']

2
David Brilliant

Für die Indizes 0 und 2 aus Liste A:

for x in (2,0): listA.pop(x)

Für einige zufällige Indizes, die aus listA entfernt werden sollen:

indices=(5,3,2,7,0) 
for x in sorted(indices)[::-1]: listA.pop(x)
2
jam

Sie können diese Logik verwenden:

my_list = ['Word','yes','no','Nice']

c=[b for i,b in enumerate(my_list) if not i in (0,2,3)]

print c
2
raghu

Um den Kommentar von @ sth zu verallgemeinern. Das Löschen von Elementen in jeder Klasse, die abc.MutableSequence implementiert, und insbesondere in list, erfolgt über __delitem__ magische Methode. Diese Methode funktioniert ähnlich wie __getitem__, dh es kann entweder eine Ganzzahl oder ein Slice akzeptiert werden. Hier ist ein Beispiel:

class MyList(list):
    def __delitem__(self, item):
        if isinstance(item, slice):
            for i in range(*item.indices(len(self))):
                self[i] = 'null'
        else:
            self[item] = 'null'


l = MyList(range(10))
print(l)
del l[5:8]
print(l)

Dies wird ausgegeben

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

Sie können dies auf ein Diktat anwenden, nicht auf eine Liste. In einer Liste sind die Elemente der Reihe nach. In einem Diktat hängen sie nur vom Index ab.

Einfacher Code, um es zu erklären indem er tut:

>>> lst = ['a','b','c']
>>> dct = {0: 'a', 1: 'b', 2:'c'}
>>> lst[0]
'a'
>>> dct[0]
'a'
>>> del lst[0]
>>> del dct[0]
>>> lst[0]
'b'
>>> dct[0]
Traceback (most recent call last):
  File "<pyshell#19>", line 1, in <module>
    dct[0]
KeyError: 0
>>> dct[1]
'b'
>>> lst[1]
'c'

Eine Möglichkeit, eine Liste in einem Diktat "umzuwandeln", ist:

>>> dct = {}
>>> for i in xrange(0,len(lst)): dct[i] = lst[i]

Das Gegenteil ist:

lst = [dct[i] for i in sorted(dct.keys())] 

Wie Sie sagten, ist es auf jeden Fall besser, mit dem Löschen aus dem höheren Index zu beginnen.

1
Andrea Ambu

Ich kann mir zwei Möglichkeiten vorstellen:

  1. schneide die Liste wie folgt (dies löscht das 1., 3. und 8. Element)

    somelist = Somelist [1: 2] + Somelist [3: 7] + Somelist [8:]

  2. tun Sie dies an Ort und Stelle, aber nacheinander:

    somelist.pop (2) somelist.pop (0)

Das Importieren nur aus diesem Grund ist möglicherweise zu viel des Guten, aber wenn Sie trotzdem pandas verwenden, ist die Lösung einfach und unkompliziert:

import pandas as pd
stuff = pd.Series(['a','b','a','c','a','d'])
less_stuff = stuff[stuff != 'a']  # define any condition here
# results ['b','c','d']
1
Lorinc Nyitrai

Eine weitere Umsetzung der Idee, aus dem höchsten Index zu entfernen.

for i in range(len(yourlist)-1, -1, -1):
    del yourlist(i)
1
bakka
some_list.remove(some_list[max(i, j)])

Vermeidet das Sortieren von Kosten und das explizite Kopieren von Listen.

1
Chester

Wie wäre es mit einem von diesen (ich bin sehr neu in Python, aber sie scheinen ok):

ocean_basin = ['a', 'Atlantic', 'Pacific', 'Indian', 'a', 'a', 'a']
for i in range(1, (ocean_basin.count('a') + 1)):
    ocean_basin.remove('a')
print(ocean_basin)

['Atlantic', 'Pacific', 'Indian']

ob = ['a', 'b', 4, 5,'Atlantic', 'Pacific', 'Indian', 'a', 'a', 4, 'a']
remove = ('a', 'b', 4, 5)
ob = [i for i in ob if i not in (remove)]
print(ob)

['Atlantic', 'Pacific', 'Indian']

0
user12001090