Domanda

Ho due liste in Python, come questi:

temp1 = ['One', 'Two', 'Three', 'Four']
temp2 = ['One', 'Two']

Ho bisogno di creare un terzo elenco con gli elementi dalla prima lista che non sono presenti nella seconda. Dall'esempio devo andare:

temp3 = ['Three', 'Four']

Ci sono modi veloci senza cicli e controllo?

È stato utile?

Soluzione

In [5]: list(set(temp1) - set(temp2))
Out[5]: ['Four', 'Three']

Attenzione che

In [5]: set([1, 2]) - set([2, 3])
Out[5]: set([1]) 

in cui ci si potrebbe aspettare / vuole che uguale set([1, 3]). Se si vuole set([1, 3]) come la tua risposta, è necessario l'uso set([1, 2]).symmetric_difference(set([2, 3])).

Altri suggerimenti

Le soluzioni esistenti tutte offrono l'uno o l'altro di:

  • Più veloce di O (n * m) prestazioni.
  • ordine di lista di input Preserve.

Ma finora nessuna soluzione ha entrambi. Se si desidera che sia, provate questo:

s = set(temp2)
temp3 = [x for x in temp1 if x not in s]

Performance test

import timeit
init = 'temp1 = list(range(100)); temp2 = [i * 2 for i in range(50)]'
print timeit.timeit('list(set(temp1) - set(temp2))', init, number = 100000)
print timeit.timeit('s = set(temp2);[x for x in temp1 if x not in s]', init, number = 100000)
print timeit.timeit('[item for item in temp1 if item not in temp2]', init, number = 100000)

Risultati:

4.34620224079 # ars' answer
4.2770634955  # This answer
30.7715615392 # matt b's answer

Il metodo che ho presentato, così come mantenere l'ordine è anche (un po ') più veloce rispetto alla sottrazione set perché non richiede la costruzione di un insieme inutile. La differenza di prestazioni sarebbe più inferme se il primo elenco è notevolmente più lungo del secondo e se hashing è costoso. Ecco un secondo test che dimostra questo:

init = '''
temp1 = [str(i) for i in range(100000)]
temp2 = [str(i * 2) for i in range(50)]
'''

Risultati:

11.3836875916 # ars' answer
3.63890368748 # this answer (3 times faster!)
37.7445402279 # matt b's answer
temp3 = [item for item in temp1 if item not in temp2]

La differenza tra due liste (diciamo List1 e List2) può essere trovata usando la seguente semplice funzione.

def diff(list1, list2):
    c = set(list1).union(set(list2))  # or c = set(list1) | set(list2)
    d = set(list1).intersection(set(list2))  # or d = set(list1) & set(list2)
    return list(c - d)

o

def diff(list1, list2):
    return list(set(list1).symmetric_difference(set(list2)))  # or return list(set(list1) ^ set(list2))

utilizzando la funzione di cui sopra, la differenza può essere trovato utilizzando diff(temp2, temp1) o diff(temp1, temp2). Sia darà la ['Four', 'Three'] risultato. Non dovete preoccuparvi di l'ordine della lista, o che la lista deve essere data prima.

Python di riferimento doc

Nel caso in cui si desidera che la differenza in modo ricorsivo, ho scritto un pacchetto per python: https://github.com/seperman/deepdiff

Installazione

Installa da Cheese Shop:

pip install deepdiff

Utilizzo Esempio

L'importazione

>>> from deepdiff import DeepDiff
>>> from pprint import pprint
>>> from __future__ import print_function # In case running on Python 2

restituisce lo stesso oggetto vuoto

>>> t1 = {1:1, 2:2, 3:3}
>>> t2 = t1
>>> print(DeepDiff(t1, t2))
{}

Tipo di un elemento è cambiato

>>> t1 = {1:1, 2:2, 3:3}
>>> t2 = {1:1, 2:"2", 3:3}
>>> pprint(DeepDiff(t1, t2), indent=2)
{ 'type_changes': { 'root[2]': { 'newtype': <class 'str'>,
                                 'newvalue': '2',
                                 'oldtype': <class 'int'>,
                                 'oldvalue': 2}}}

valore di un elemento è cambiato

>>> t1 = {1:1, 2:2, 3:3}
>>> t2 = {1:1, 2:4, 3:3}
>>> pprint(DeepDiff(t1, t2), indent=2)
{'values_changed': {'root[2]': {'newvalue': 4, 'oldvalue': 2}}}

Articolo aggiunto e / o rimosso

>>> t1 = {1:1, 2:2, 3:3, 4:4}
>>> t2 = {1:1, 2:4, 3:3, 5:5, 6:6}
>>> ddiff = DeepDiff(t1, t2)
>>> pprint (ddiff)
{'dic_item_added': ['root[5]', 'root[6]'],
 'dic_item_removed': ['root[4]'],
 'values_changed': {'root[2]': {'newvalue': 4, 'oldvalue': 2}}}

differenza Stringa

>>> t1 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":"world"}}
>>> t2 = {1:1, 2:4, 3:3, 4:{"a":"hello", "b":"world!"}}
>>> ddiff = DeepDiff(t1, t2)
>>> pprint (ddiff, indent = 2)
{ 'values_changed': { 'root[2]': {'newvalue': 4, 'oldvalue': 2},
                      "root[4]['b']": { 'newvalue': 'world!',
                                        'oldvalue': 'world'}}}

Stringa differenza 2

>>> t1 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":"world!\nGoodbye!\n1\n2\nEnd"}}
>>> t2 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":"world\n1\n2\nEnd"}}
>>> ddiff = DeepDiff(t1, t2)
>>> pprint (ddiff, indent = 2)
{ 'values_changed': { "root[4]['b']": { 'diff': '--- \n'
                                                '+++ \n'
                                                '@@ -1,5 +1,4 @@\n'
                                                '-world!\n'
                                                '-Goodbye!\n'
                                                '+world\n'
                                                ' 1\n'
                                                ' 2\n'
                                                ' End',
                                        'newvalue': 'world\n1\n2\nEnd',
                                        'oldvalue': 'world!\n'
                                                    'Goodbye!\n'
                                                    '1\n'
                                                    '2\n'
                                                    'End'}}}

>>> 
>>> print (ddiff['values_changed']["root[4]['b']"]["diff"])
--- 
+++ 
@@ -1,5 +1,4 @@
-world!
-Goodbye!
+world
 1
 2
 End

Modifica tipo

>>> t1 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 2, 3]}}
>>> t2 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":"world\n\n\nEnd"}}
>>> ddiff = DeepDiff(t1, t2)
>>> pprint (ddiff, indent = 2)
{ 'type_changes': { "root[4]['b']": { 'newtype': <class 'str'>,
                                      'newvalue': 'world\n\n\nEnd',
                                      'oldtype': <class 'list'>,
                                      'oldvalue': [1, 2, 3]}}}

differenza List

>>> t1 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 2, 3, 4]}}
>>> t2 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 2]}}
>>> ddiff = DeepDiff(t1, t2)
>>> pprint (ddiff, indent = 2)
{'iterable_item_removed': {"root[4]['b'][2]": 3, "root[4]['b'][3]": 4}}

Lista differenza 2:

>>> t1 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 2, 3]}}
>>> t2 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 3, 2, 3]}}
>>> ddiff = DeepDiff(t1, t2)
>>> pprint (ddiff, indent = 2)
{ 'iterable_item_added': {"root[4]['b'][3]": 3},
  'values_changed': { "root[4]['b'][1]": {'newvalue': 3, 'oldvalue': 2},
                      "root[4]['b'][2]": {'newvalue': 2, 'oldvalue': 3}}}

Lista differenza ignorando ordine o duplicati: (con gli stessi dizionari come sopra)

>>> t1 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 2, 3]}}
>>> t2 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 3, 2, 3]}}
>>> ddiff = DeepDiff(t1, t2, ignore_order=True)
>>> print (ddiff)
{}

elenco che contiene dizionario:

>>> t1 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 2, {1:1, 2:2}]}}
>>> t2 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 2, {1:3}]}}
>>> ddiff = DeepDiff(t1, t2)
>>> pprint (ddiff, indent = 2)
{ 'dic_item_removed': ["root[4]['b'][2][2]"],
  'values_changed': {"root[4]['b'][2][1]": {'newvalue': 3, 'oldvalue': 1}}}

Set:

>>> t1 = {1, 2, 8}
>>> t2 = {1, 2, 3, 5}
>>> ddiff = DeepDiff(t1, t2)
>>> pprint (DeepDiff(t1, t2))
{'set_item_added': ['root[3]', 'root[5]'], 'set_item_removed': ['root[8]']}

nome tuple:

>>> from collections import namedtuple
>>> Point = namedtuple('Point', ['x', 'y'])
>>> t1 = Point(x=11, y=22)
>>> t2 = Point(x=11, y=23)
>>> pprint (DeepDiff(t1, t2))
{'values_changed': {'root.y': {'newvalue': 23, 'oldvalue': 22}}}

Oggetti personalizzato:

>>> class ClassA(object):
...     a = 1
...     def __init__(self, b):
...         self.b = b
... 
>>> t1 = ClassA(1)
>>> t2 = ClassA(2)
>>> 
>>> pprint(DeepDiff(t1, t2))
{'values_changed': {'root.b': {'newvalue': 2, 'oldvalue': 1}}}

attributo dell'oggetto ha aggiunto:

>>> t2.c = "new attribute"
>>> pprint(DeepDiff(t1, t2))
{'attribute_added': ['root.c'],
 'values_changed': {'root.b': {'newvalue': 2, 'oldvalue': 1}}}

Se cercate delle prestazioni, quindi utilizzare NumPy!

Ecco il notebook pieno come un succo su GitHub con confronto tra lista, NumPy, e panda.

https://gist.github.com/denfromufa/2821ff59b02e9482be15d27f2bbd4451

 entrare descrizione dell'immagine qui

La maggior parte modo semplice,

utilizzo set (). Differenza (set ())

list_a = [1,2,3]
list_b = [2,3]
print set(list_a).difference(set(list_b))

risposta è set([1])

può stampare come una lista,

print list(set(list_a).difference(set(list_b)))

i getterò in quanto nessuno dei presenti soluzioni resa una tupla:

temp3 = tuple(set(temp1) - set(temp2))

In alternativa:

#edited using @Mark Byers idea. If you accept this one as answer, just accept his instead.
temp3 = tuple(x for x in temp1 if x not in set(temp2))

Come le altre risposte non tuple rendimento in questa direzione, conserva ordine

Può essere fatto utilizzando operatore python XOR.

  • Questo consente di eliminare i duplicati in ogni elenco
  • Questo mostrerà differenza di temp1 da temp2 e temp2 da temp1.

set(temp1) ^ set(temp2)

Volevo qualcosa che avrebbe preso due liste e potrebbe fare ciò che diff in bash fa. Dal momento che questa domanda si apre per prima quando si esegue una ricerca per "python diff due liste" e non è molto specifico, mi post quello che mi è venuta.

SequenceMather da difflib è possibile confrontare due liste come diff fa. Nessuna delle altre risposte vi dirà la posizione in cui si verifica la differenza, ma questo lo fa. Alcune risposte danno la differenza in una sola direzione. Alcuni riordinare gli elementi. Alcuni non gestire i duplicati. Ma questa soluzione ti dà una vera differenza tra due liste:

a = 'A quick fox jumps the lazy dog'.split()
b = 'A quick brown mouse jumps over the dog'.split()

from difflib import SequenceMatcher

for tag, i, j, k, l in SequenceMatcher(None, a, b).get_opcodes():
  if tag == 'equal': print('both have', a[i:j])
  if tag in ('delete', 'replace'): print('  1st has', a[i:j])
  if tag in ('insert', 'replace'): print('  2nd has', b[k:l])

Questa uscite:

both have ['A', 'quick']
  1st has ['fox']
  2nd has ['brown', 'mouse']
both have ['jumps']
  2nd has ['over']
both have ['the']
  1st has ['lazy']
both have ['dog']

Naturalmente, se la vostra applicazione fa le stesse ipotesi le altre risposte fanno, si potranno beneficiare di loro la maggior parte. Ma se siete alla ricerca di una funzionalità diff vero, allora questo è l'unico modo per andare.

Per esempio, nessuna delle altre risposte in grado di gestire:

a = [1,2,3,4,5]
b = [5,4,3,2,1]

Ma questo fa:

  2nd has [5, 4, 3, 2]
both have [1]
  1st has [2, 3, 4, 5]

Prova questo:

temp3 = set(temp1) - set(temp2)

questo potrebbe essere anche più veloce di comprensione elenco di Mark:

list(itertools.filterfalse(set(temp2).__contains__, temp1))

Ecco una risposta Counter per il caso più semplice.

Questo è più breve di quello di cui sopra che fa diff bidirezionali perché fa solo esattamente ciò che la domanda chiede:. Generare un elenco di ciò che è nel primo elenco, ma non la seconda

from collections import Counter

lst1 = ['One', 'Two', 'Three', 'Four']
lst2 = ['One', 'Two']

c1 = Counter(lst1)
c2 = Counter(lst2)
diff = list((c1 - c2).elements())

In alternativa, a seconda delle vostre preferenze di leggibilità, si fa per un dignitoso one-liner:

diff = list((Counter(lst1) - Counter(lst2)).elements())

Output:

['Three', 'Four']

Si noti che è possibile rimuovere la chiamata list(...) se sono solo iterando su di esso.

A causa di questa soluzione utilizza i contatori, gestisce quantità correttamente vs le molte risposte di set-based. Ad esempio, su questo ingresso:

lst1 = ['One', 'Two', 'Two', 'Two', 'Three', 'Three', 'Four']
lst2 = ['One', 'Two']

L'output è:

['Two', 'Two', 'Three', 'Three', 'Four']

Si potrebbe utilizzare un metodo ingenuo se gli elementi del difflist vengono ordinati e imposta.

list1=[1,2,3,4,5]
list2=[1,2,3]

print list1[len(list2):]

o con metodi set nativi:

subset=set(list1).difference(list2)

print subset

import timeit
init = 'temp1 = list(range(100)); temp2 = [i * 2 for i in range(50)]'
print "Naive solution: ", timeit.timeit('temp1[len(temp2):]', init, number = 100000)
print "Native set solution: ", timeit.timeit('set(temp1).difference(temp2)', init, number = 100000)

soluzione Naive: ,0787101593292

set di soluzioni Native: 0,998837615564

Sono poco e troppo tardi nel gioco per questo, ma si può fare un confronto tra le prestazioni di alcune delle sopra codice di cui al presente, due dei contendenti più veloci sono,

list(set(x).symmetric_difference(set(y)))
list(set(x) ^ set(y))

Mi scuso per il livello elementare di codifica.

import time
import random
from itertools import filterfalse

# 1 - performance (time taken)
# 2 - correctness (answer - 1,4,5,6)
# set performance
performance = 1
numberoftests = 7

def answer(x,y,z):
    if z == 0:
        start = time.clock()
        lists = (str(list(set(x)-set(y))+list(set(y)-set(y))))
        times = ("1 = " + str(time.clock() - start))
        return (lists,times)

    elif z == 1:
        start = time.clock()
        lists = (str(list(set(x).symmetric_difference(set(y)))))
        times = ("2 = " + str(time.clock() - start))
        return (lists,times)

    elif z == 2:
        start = time.clock()
        lists = (str(list(set(x) ^ set(y))))
        times = ("3 = " + str(time.clock() - start))
        return (lists,times)

    elif z == 3:
        start = time.clock()
        lists = (filterfalse(set(y).__contains__, x))
        times = ("4 = " + str(time.clock() - start))
        return (lists,times)

    elif z == 4:
        start = time.clock()
        lists = (tuple(set(x) - set(y)))
        times = ("5 = " + str(time.clock() - start))
        return (lists,times)

    elif z == 5:
        start = time.clock()
        lists = ([tt for tt in x if tt not in y])
        times = ("6 = " + str(time.clock() - start))
        return (lists,times)

    else:    
        start = time.clock()
        Xarray = [iDa for iDa in x if iDa not in y]
        Yarray = [iDb for iDb in y if iDb not in x]
        lists = (str(Xarray + Yarray))
        times = ("7 = " + str(time.clock() - start))
        return (lists,times)

n = numberoftests

if performance == 2:
    a = [1,2,3,4,5]
    b = [3,2,6]
    for c in range(0,n):
        d = answer(a,b,c)
        print(d[0])

elif performance == 1:
    for tests in range(0,10):
        print("Test Number" + str(tests + 1))
        a = random.sample(range(1, 900000), 9999)
        b = random.sample(range(1, 900000), 9999)
        for c in range(0,n):
            #if c not in (1,4,5,6):
            d = answer(a,b,c)
            print(d[1])

Questa è un'altra soluzione:

def diff(a, b):
    xa = [i for i in set(a) if i not in b]
    xb = [i for i in set(b) if i not in a]
    return xa + xb

Se si esegue in TypeError: unhashable type: 'list' è necessario svoltare a liste o gruppi in tuple, per es.

set(map(tuple, list_of_lists1)).symmetric_difference(set(map(tuple, list_of_lists2)))

Come confrontare una lista di liste / set in Python?

Qui ci sono alcune semplici, fine-preservare modi di diffing due liste di stringhe.

Codice

Un approccio insolito utilizzando pathlib :

import pathlib


temp1 = ["One", "Two", "Three", "Four"]
temp2 = ["One", "Two"]

p = pathlib.Path(*temp1)
r = p.relative_to(*temp2)
list(r.parts)
# ['Three', 'Four']

Questo presuppone entrambi gli elenchi contengono stringhe con inizio equivalenti. per maggiori dettagli, vedere la docs . Nota, non è particolarmente veloce rispetto alle operazioni di set.


Un'implementazione straight-forward utilizzando itertools.zip_longest :

import itertools as it


[x for x, y in it.zip_longest(temp1, temp2) if x != y]
# ['Three', 'Four']

versione a linea singola di arulmr soluzione

def diff(listA, listB):
    return set(listA) - set(listB) | set(listA) -set(listB)

se volete qualcosa di più simile a un insieme di modifiche ... potrebbe usare Contatore

from collections import Counter

def diff(a, b):
  """ more verbose than needs to be, for clarity """
  ca, cb = Counter(a), Counter(b)
  to_add = cb - ca
  to_remove = ca - cb
  changes = Counter(to_add)
  changes.subtract(to_remove)
  return changes

lista = ['one', 'three', 'four', 'four', 'one']
listb = ['one', 'two', 'three']

In [127]: diff(lista, listb)
Out[127]: Counter({'two': 1, 'one': -1, 'four': -2})
# in order to go from lista to list b, you need to add a "two", remove a "one", and remove two "four"s

In [128]: diff(listb, lista)
Out[128]: Counter({'four': 2, 'one': 1, 'two': -1})
# in order to go from listb to lista, you must add two "four"s, add a "one", and remove a "two"

Si può calcolare intersezione meno unione di liste:

temp1 = ['One', 'Two', 'Three', 'Four']
temp2 = ['One', 'Two', 'Five']

set(temp1+temp2)-(set(temp1)&set(temp2))

Out: set(['Four', 'Five', 'Three']) 

Questo può essere risolto con una linea. La domanda è dato due liste (Temp1 e Temp2) restituiscono la loro differenza in un terzo elenco (TEMP3).

temp3 = list(set(temp1).difference(set(temp2)))

diciamo Let abbiamo due liste

list1 = [1, 3, 5, 7, 9]
list2 = [1, 2, 3, 4, 5]

si può vedere da quanto sopra due liste che articoli 1, 3, 5 esistono in lista2 e articoli 7, 9 non lo fanno. D'altra parte, articoli 1, 3, 5 esistono in lista1 e articoli 2, 4 non lo fanno.

Qual è la soluzione migliore per restituire un nuovo elenco contenente articoli 7, 9 e 2, 4?

Tutte le risposte sopra trovano la soluzione, ora che cosa è il più ottimale?

def difference(list1, list2):
    new_list = []
    for i in list1:
        if i not in list2:
            new_list.append(i)

    for j in list2:
        if j not in list1:
            new_list.append(j)
    return new_list

vs

def sym_diff(list1, list2):
    return list(set(list1).symmetric_difference(set(list2)))

Utilizzando timeit possiamo vedere i risultati

t1 = timeit.Timer("difference(list1, list2)", "from __main__ import difference, 
list1, list2")
t2 = timeit.Timer("sym_diff(list1, list2)", "from __main__ import sym_diff, 
list1, list2")

print('Using two for loops', t1.timeit(number=100000), 'Milliseconds')
print('Using two for loops', t2.timeit(number=100000), 'Milliseconds')

ritorna

[7, 9, 2, 4]
Using two for loops 0.11572412995155901 Milliseconds
Using symmetric_difference 0.11285737506113946 Milliseconds

Process finished with exit code 0

Ecco un modo semplice per distinguere due liste (quali che siano i contenuti sono), è possibile ottenere il risultato come illustrato di seguito:

>>> from sets import Set
>>>
>>> l1 = ['xvda', False, 'xvdbb', 12, 'xvdbc']
>>> l2 = ['xvda', 'xvdbb', 'xvdbc', 'xvdbd', None]
>>>
>>> Set(l1).symmetric_difference(Set(l2))
Set([False, 'xvdbd', None, 12])

auguriamo che questo utile.

(list(set(a)-set(b))+list(set(b)-set(a)))
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top