2016-04-29 19 views
7

Supponiamo che ho una lista L di sconosciuti oggetti, O1 a On, e voglio togliere un altro riferimento all'oggetto M che può riferirsi a uno dei gli oggetti in L, sono riuscito a farlo utilizzando:modo più veloce o più idiomatico per rimuovere l'oggetto dalla lista di oggetti in Python

L = [ O1, O2, ... On] 

... 

L = [ j for j in L if j not in [ M ] ] 

che è incantevole e idiomatica ... ma sto avendo a che fare molto, e mi chiedo se non c'è un altro modo più idiomatico , o se non c'è un modo più veloce.

Il punto importante è che l'elenco degli oggetti è sconosciuta, e può o non può includere l'oggetto da escludere. Voglio evitare di estendere o sottoclasse gli oggetti laddove possibile.

+1

La comprensione delle liste sarà il modo più veloce (le comprensioni delle liste sono generalmente più veloci in Python + sarà con O (n) complessità). In una nota a margine, se 'M' è un singolo oggetto, perché dovresti voler fare' j non in [M] '? 'j == M' sarà sicuramente un po 'più veloce in quanto i confronti diretti sono sempre più veloci. –

+0

'prova: L.remove (M) tranne ValueError: pass'? Tuttavia il metodo 'remove' rimuove solo il primo elemento uguale a' M'. – Bakuriu

+0

possono esserci più di una istanza di M nell'elenco? – skrrgwasme

risposta

5

list.remove sembra essere il modo più veloce , con la lista di comprensione come il secondo più veloce e finalmente filter.

Ecco i risultati timeit

In: python -m timeit '[x for x in [1,2,3,4,5] if x not in [4]]' 
Out: 1000000 loops, best of 3: 0.285 usec per loop 

In: python -m timeit '[x for x in [1,2,3,4,5] if x != 4]' 
Out: 1000000 loops, best of 3: 0.254 usec per loop 

In: python -m timeit 'filter(lambda x: x not in [4], [1,2,3,4,5])' 
Out: 1000000 loops, best of 3: 0.577 usec per loop 

In: python -m timeit 'filter(lambda x: x != 4, [1,2,3,4,5])' 
Out: 1000000 loops, best of 3: 0.569 usec per loop 

In: python -m timeit '[1,2,3,4,5].remove(4)' 
Out: 10000000 loops, best of 3: 0.132 usec per loop 
+1

L'intenzione è anche la più chiara. – skrrgwasme

+2

I tuoi risultati per la rimozione sono troppo ottimisti, perché dovresti aggiungere un 'try except' per catturare un possibile' ValueError'. Ma sono d'accordo con te è ancora il modo migliore - purché OP desideri cambiare la lista originale perché altri metodi ne costruiscono una copia .. –

+0

Concordato sulla Prova. Grazie a @Muhammad – Dycey

2

E la funzione integrata filter?

>>> l = [1,2,3,4,5] 
>>> f = [4] 
>>> filter(lambda x: x not in f, l) 
[1, 2, 3, 5] 

o in python3

>>> list(filter(lambda x: x not in f, l)) 
[1, 2, 3, 5] 
+0

Nota: questo ** non ** restituisce un 'elenco' in python3 +. – Bakuriu

+0

ha aggiunto la versione python3 – Francesco

2

Usa try/except avvolto in una ricorsiva funzione ricorsione si prende cura di eventuali molteplici M 's

def tremove(L, M): 
    try: 
     L.remove(M) 
     return tremove(L, M) 
    except: 
     return L 

tremove(L, M) 
2

Se ci sono più occorrenze del valore del allora probabilmente è necessario un -loop while con remove:

L = [1,2,3,4,5] 
while True: 
    try: 
     L.remove(4) 
    except: 
     break 

E 'un po' più lento (a causa di la gestione delle eccezioni e più iterazioni sulla lista) rispetto alla comprensione della lista:

[ j for j in L if j != 4 ] 

ma entrambi funzionano bene. Se si desidera escludere più valori allora si dovrebbe utilizzare l'elenco-di comprensione:

M = [1, 4] 
[ j for j in L if j not in M ] 

perché il try/except saranno annidati e la lista di comprensione ha solo bisogno di attraversare la lista una volta.

2

Ecco un'idea che consente di effettuare controlli di contenimento O (1) per gli elementi lavabili. Dovrebbe essere notevolmente più veloce per le lunghe liste M con molti hashables.

class MixedBag(object): 
    def __init__(self, *args): 
     self.hashed = set() 
     self.nothashed = [] 

     for x in args: 
      self.add(x) 

    def add(self, x): 
     try: 
      self.hashed.add(x) 
     except TypeError: 
      self.nothashed.append(x) 

    def __contains__(self, x): 
     try: 
      return x in self.hashed 
     except TypeError: 
      return x in self.nothashed 


L = [[1,2,3], 4, '5', {6}] 
M = [[1,2,3], '5', {4}] 

mix = MixedBag(*M) 
L = [x for x in L if x not in mix] 
print(L) # [4, set([6])]