2016-01-30 119 views
5

Queste sono le mie due liste;Python - Intersezione di due liste di liste

k = [[1, 2], [4], [5, 6, 2], [1, 2], [3], [4], [5,9]] 
kDash = [[1, 2], [4], [5, 6, 2], [1, 2], [3], [4], [5,6], [1,2]] 

La mia uscita dovrebbe essere la seguente;

[[1, 2], [4], [5, 6, 2], [1, 2], [3], [4]] 

come posso arrivare a questa uscita?

grazie in anticipo

+0

Il problema che ho trovato era che l'incapacità di convertire una lista di liste ad un insieme, se possibile questo incrocio potrebbe essere presa facilmente –

+0

spiegare la logica con cui si ottiene l'output. – timgeb

+0

Puoi spiegare perché '[5, 6]' e '[5, 9]' sono nell'intersezione? – NiziL

risposta

4

Si dovrà convertire le liste alla lista di tuple, e quindi utilizzare l'incrocio. Nota che sotto soluzione possono avere elementi in un ordine diverso, e ovviamente i duplicati non saranno lì, dal momento che sto usando set.

In [1]: l1 = [[1, 2], [4], [5, 6, 2], [1, 2], [3], [4], [5,9]] 

In [2]: l2 = [[1, 2], [4], [5, 6, 2], [1, 2], [3], [4], [5,6], [1,2]] 

In [3]: [list(x) for x in set(tuple(x) for x in l1).intersection(set(tuple(x) for x in l2))] 
Out[3]: [[1, 2], [5, 6, 2], [3], [4]] 

È possibile in alternativa, salvare l'incrocio in una variabile e ottiene l'elenco definitivo, se l'ordine, sono necessari i duplicati:

In [4]: intersection = set(tuple(x) for x in l1).intersection(set(tuple(x) for x in l2)) 

In [5]: [x for x in l1 if tuple(x) in intersection] 
Out[5]: [[1, 2], [4], [5, 6, 2], [1, 2], [3], [4]] 

e l'intersezione, nel caso in cui, se siete interessati.

In [6]: print intersection 
set([(1, 2), (5, 6, 2), (3,), (4,)]) 

Questo funziona abbastanza bene per grandi liste, ma se le liste sono piccole, non esplorare l'altra soluzione da @timegb (la cui soluzione sarà altamente unoptimal per liste più lunghe)

3

Dal momento che la vostra lista di uscita ha elementi duplicati, non sembra proprio che vogliate un'intersezione classica. Una comprensione di base della lista farà tutto.

>>> k = [[1, 2], [4], [5, 6, 2], [1, 2], [3], [4], [5,9]] 
>>> kDash = [[1, 2], [4], [5, 6, 2], [1, 2], [3], [4], [5,6], [1,2]] 
>>> [x for x in k if x in kDash] 
[[1, 2], [4], [5, 6, 2], [1, 2], [3], [4]] 

Per grandi liste, vogliamo ottenere il tempo necessario per chiamare __contains__ a O (1) invece di O (n):

>>> stuff_in_kDash = set(map(tuple, kDash)) 
>>> [x for x in k if tuple(x) in stuff_in_kDash] 
[[1, 2], [4], [5, 6, 2], [1, 2], [3], [4]] 
+0

E se hai bisogno di rimuovere l'elemento duplicato, puoi dare un'occhiata a [questa risposta] (http://stackoverflow.com/questions/2213923/python-removing-duplicates -da una lista-di-liste);) – NiziL

+1

Questo sarà un * lotto * più lento dei metodi di intersezione 'set'. Il ridimensionamento è qualcosa come 'O (n²k)' dove 'n' è il numero di sottoliste e' k' è la lunghezza media di ogni sottolista. – Veedrac

+0

Ho appena realizzato che l'elenco di output degli OP ha elementi duplicati. Quindi la lista comp è la strada da percorrere a meno che le specifiche cambino. – timgeb

2

un modo più pulito di scrivere l'incrocio è

{tuple(x) for x in l1} & {tuple(x) for x in l2} 

Una buona alternativa è

{tuple(x) for x in l1}.intersection(map(tuple, l2)) 
0

Anche se ciò che è stato scritto qui è molto più elegante soluzioni, eccone un altro

def foo(L1,L2): 
    res=[] 
    for lst in L1: 
     if lst in L2: 
      res.append(lst) 
    return res