2012-04-04 10 views
11

sto facendo un'operazione di differenza set in Python:ordine di ritegno durante l'utilizzo differenza set di Python

from sets import Set 
from mongokit import ObjectId 
x = [ObjectId("4f7aba8a43f1e51544000006"), ObjectId("4f7abaa043f1e51544000007"), ObjectId("4f7ac02543f1e51a44000001")] 
y = [ObjectId("4f7acde943f1e51fb6000003")] 
print list(Set(x).difference(Set(y))) 

sto ottenendo:

[ObjectId('4f7abaa043f1e51544000007'), ObjectId('4f7ac02543f1e51a44000001'), ObjectId('4f7aba8a43f1e51544000006')] 

ho bisogno di ottenere il primo elemento per la prossima operazione che è importante Come posso mantenere l'elenco x nel formato originale?

+3

set sono per definizione non ordinato. – icktoofay

+4

E non dovresti mai usare il modulo 'sets'. Usa il tipo 'set' incorporato. –

+3

Il tipo * set.Set * è una scelta ragionevole per chi ha bisogno di compatibilità con le versioni precedenti di Python. Il tipo * set * incorporato è stato modellato dopo * set.Set * - entrambi funzionano bene per la maggior parte delle applicazioni (anche se la versione integrata è più veloce). –

risposta

4

Si potrebbe solo fare questo

diff = set(x) - set(y) 
[item for item in x if item in diff] 

o

filter(diff.__contains__, x) 
+0

E se lo fai con un gran numero di elementi in 'y' o molte volte, lavorare su' set (y) 'piuttosto che' y' potrebbe essere più veloce. –

+0

Ok, non ero sicuro della velocità, ma se ne sei sicuro, immagino che sia il migliore. – jamylak

+0

È qualcosa che vorresti controllare. –

11

insiemi non sono ordinati, per cui sarà necessario per mettere i risultati indietro nell'ordine corretto dopo aver fatto la vostra differenza set. Fortunatamente hai già gli elementi nell'ordine che desideri, quindi è facile.

diff = set(x) - set(y) 
result = [o for o in x if o in diff] 

Ma questo può essere ottimizzato; puoi fare la differenza come parte della comprensione della lista (anche se è probabilmente leggermente meno chiaro che è quello che stai facendo).

sety = set(y) 
result = [o for o in x if o not in sety] 

si potrebbe anche farlo senza creare il set da y, ma il set fornirà test di appartenenza veloci, che vi farà risparmiare tempo significativo se uno dei due elenchi è di grandi dimensioni.

+0

Quando dici semplificato, intendi in performance? – jamylak

+0

nvm, pensato che deve essere più veloce. – jamylak

+0

Leggermente più veloce, sì. Dovrà solo attraversare la lista 'x' una volta invece di due volte. – kindall

17

Sembra che sia necessario un set ordinato anziché un set normale.

>>> x = [ObjectId("4f7aba8a43f1e51544000006"), ObjectId("4f7abaa043f1e51544000007"), ObjectId("4f7ac02543f1e51a44000001")] 
>>> y = [ObjectId("4f7acde943f1e51fb6000003")] 
>>> print list(OrderedSet(x) - OrderedSet(y)) 
[ObjectId("4f7aba8a43f1e51544000006"), ObjectId("4f7abaa043f1e51544000007"), ObjectId("4f7ac02543f1e51a44000001")] 

Python non sono dotati di un insieme ordinato, ma è facile fare uno:

import collections 

class OrderedSet(collections.Set): 

    def __init__(self, iterable=()): 
     self.d = collections.OrderedDict.fromkeys(iterable) 

    def __len__(self): 
     return len(self.d) 

    def __contains__(self, element): 
     return element in self.d 

    def __iter__(self): 
     return iter(self.d) 

Spero che questo aiuti :-)