2013-04-01 5 views

Antwort

25
>>> suits = ["h","c", "d", "s"] 
>>> noclubs = list(suits) 
>>> noclubs.remove("c") 
>>> noclubs 
['h', 'd', 's'] 

Wenn Sie nicht benötigen eine separate noclubs

>>> suits = ["h","c", "d", "s"] 
>>> suits.remove("c") 
24
suits = ["h","c", "d", "s"] 

noclubs = [x for x in suits if x != "c"] 
+0

Ich kann nicht lügen ... Ich hatte gehofft, dass es etwas ohne eine Schleife geben würde. Dies ist viel kürzer und intuitiver in Sprachen wie R. –

+0

Ich würde diese Lösung vermeiden, da sie mir ziemlich unoptimiert erscheint. Mit .remove() ist IMHO viel schneller. –

+0

@VisgeanSkeloru Ich würde nicht zustimmen, dass '.remove()' "viel schneller" ist. Ich habe unten eine Antwort geschrieben, um das Problem zu beheben (es ist schwierig, den Code im Kommentarfeld zu formatieren). – alukach

0

Wenn es wichtig ist, dass Sie ein spezifischen Element entfernt werden soll (im Gegensatz zu nur Filterung), Sie‘ Ich möchte etwas in der Nähe der folgenden:

noclubs = [x for i, x in enumerate(suits) if i != suits.index('c')] 

Sie können auch in Betracht ziehen Verwenden Sie eine set hier semantisch korrekt zu sein, wenn Ihr Problem in der Tat mit Karten zu spielen ist.

+1

Beachten Sie, dass diese Antwort nur den Index des ** ersten ** Vorkommens von "c" berechnet und dies für jedes Element in der ursprünglichen Liste tut. Wenn also das Original mehrere zu löschende "c" enthält, funktioniert die Funktion nicht. Und selbst wenn es nur einen enthält, wird es langsam sein. Es ist besser, nur den Wert 'if x! = 'C' zu vergleichen. – MSeifert

+0

@MSeifert, ich glaube, das war der Punkt meiner Antwort, um eine neue Liste mit einem * spezifischen * Element zu erstellen, anstatt alles zu filtern, das mit einem Prädikat übereinstimmt. Ich stimme zu, dass dies jedoch effizienter sein könnte. –

3

Iforder nicht Materie kann eine Set-Operation verwendet werden:

suits = ["h", "c", "d", "s"] 
noclubs = list(set(suits) - set(["c"])) 
# note no order guarantee, the following is the result here: 
# noclubs -> ['h', 's', 'd'] 
3

Sie Filter (oder ifilter von itertools) verwenden können

suits = ["h","c", "d", "s"] 
noclubs = filter(lambda i: i!='c', suits) 

können Sie auch Filter-Liste mit konstruieren

suits = ["h","c", "d", "s"] 
noclubs = [ i for i in suits if i!='c' ] 
18

Diese Frage wurde beantwortet, aber ich wan ted, um den Kommentar zu adressieren, dass die Verwendung des Listenverständnisses viel langsamer ist als die Verwendung von .remove().

Einige Profile von meinem Computer (mit Python 2.7.6).

%%timeit 
x = ['a', 'b', 'c', 'd'] 
y = x[:] # fastest way to copy 
y.remove('c') 

1000000 loops, best of 3: 405 ns per loop 

%%timeit 
x = ['a', 'b', 'c', 'd'] 
y = list(x) # not as fast copy 
y.remove('c') 

1000000 loops, best of 3: 689 ns per loop 

%%timeit 
x = ['a', 'b', 'c', 'd'] 
y = [n for n in x if n != 'c'] # list comprehension 

1000000 loops, best of 3: 544 ns per loop 

Wenn Sie den schnellsten Weg, um eine Liste zu kopieren (was nicht sehr gut lesbar ist), werden Sie ca. 36% schneller als Liste Verständnis mit. Aber wenn Sie die Liste kopieren, indem Sie die list() Klasse verwenden (die viel häufiger und Pythonic ist), dann werden Sie 26% langsamer sein als das Listenverständnis zu verwenden.

Wirklich, es ist alles ziemlich schnell. Ich denke, das Argument könnte gemacht werden, dass .remove() besser lesbar ist, als eine List-Verständnis-Technik aufzulisten, aber es ist nicht unbedingt schneller, es sei denn, Sie sind daran interessiert, die Lesbarkeit in der Duplizierung aufzugeben. Der große Vorteil des Listenverständnisses in diesem Szenario ist, dass es viel prägnanter ist (dh wenn Sie eine Funktion hatten, die aus irgendeinem Grund ein Element aus einer gegebenen Liste entfernen sollte, könnte dies in einer Zeile erfolgen, während die eine andere Methode würde 3 Zeilen erfordern.) Es gibt Zeiten, in denen Einzeiler sehr handlich sein können (obwohl sie typischerweise auf Kosten einiger Lesbarkeit gehen). Wenn Sie nicht wirklich wissen, ob das Element, das entfernt werden soll, tatsächlich in der Liste ist, ist das Verwenden von List-Verständnis in dem Fall von Vorteil. Während .remove() einen ValueError wirft, funktioniert Listenverstehen wie erwartet.

+3

Bitte beachten Sie auch, dass die Liste Verständnis Lösung alle "c" Zeichen entfernt, während remove() nur die erste entfernen. – Kresimir

2

Ohne für Schleifen oder Lambda-Funktionen und die Erhaltung Ordnung:

suits = ["h","c", "d", "s"] 
noclubs = suits[:suits.index("c")]+suits[suits.index("c")+1:] 

Ich bin mir bewusst, dass es intern noch Loops verwenden werden, aber zumindest Sie müssen sie nicht extern verwenden.

0

Es scheint so etwas wie dieses in Python standardmäßig nicht eingebaut zu sein.

Es gibt mehrere Antworten, aber ich würde eine mit Iteratoren hinzufügen. Wenn der Wechsel an Ort und Stelle akzeptabel ist, wird das am schnellsten. Wenn Sie das Original nicht ändern wollen und nur über einen gefilterten Satz Schleife wollen, sollte dies ziemlich schnell sein:

Umsetzung:

def without(iterable, remove_indices): 
    """ 
    Returns an iterable for a collection or iterable, which returns all items except the specified indices. 
    """ 
    if not hasattr(remove_indices, '__iter__'): 
     remove_indices = {remove_indices} 
    else: 
     remove_indices = set(remove_indices) 
    for k, item in enumerate(iterable): 
     if k in remove_indices: 
      continue 
     yield item 

Verbrauch:

li = list(range(5)) 
without(li, 3)    
# <generator object without at 0x7f6343b7c150> 
list(without(li, (0, 2))) 
# [1, 3, 4] 
list(without(li, 3))  
# [0, 1, 2, 4] 

es also ist ein Generator - Sie müssen list oder etwas aufrufen, um es dauerhaft zu machen.

Wenn Sie nur einen einzigen Index entfernen möchten, können Sie ihn natürlich noch schneller machen, indem Sie k == remove_index anstelle eines Satzes verwenden.

0

Eine Möglichkeit wäre, verwenden filter:

>>> import operator 
>>> import functools 

>>> suits = ["h", "c", "d", "s"] 

>>> # Python 3.x 
>>> list(filter(functools.partial(operator.ne, 'c'), suits)) 
['h', 'd', 's'] 

>>> # Python 2.x 
>>> filter(functools.partial(operator.ne, 'c'), suits) 
['h', 'd', 's'] 

Anstelle des partial man könnte auch die __ne__ Methode von 'c' verwenden hier:

>>> list(filter('c'.__ne__, suits)) 
['h', 'd', 's'] 

jedoch der letztere Ansatz ist nicht sehr angesehen Pythonic (normalerweise sollten Sie keine speziellen Methoden verwenden - beginnend mit Doppelunterstrichen - direkt) und es könnte geben seltsame Ergebnisse, wenn t Die Liste enthält gemischte Typen, könnte aber etwas schneller sein als der partial Ansatz.

suits = ["h", "c", "d", "s"]*200 # more elements for more stable timings 
%timeit list(filter('c'.__ne__, suits)) 
# 164 µs ± 5.98 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each) 
%timeit list(filter(functools.partial(operator.ne, 'c'), suits)) 
# 337 µs ± 13.3 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each) 
%timeit list(filter(lambda x: x != 'c', suits)) 
# 410 µs ± 13.7 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each) 
%timeit [x for x in suits if x != "c"] 
181 µs ± 465 ns per loop (mean ± std. dev. of 7 runs, 1000 loops each) 

Python 3.5.2 mit Magie IPythons %timeit Befehl getestet.

Verwandte Themen