2017-04-06 5 views
2
old = [('ver','1121'),('sign','89'),('address','A45'),('type','00')] 
new = [('ver','1121'),('sign','89'),('type','01')] 

ich die new Liste gegen old ein basierend auf dem ersten Element der Tupel vergleichen müssen, und zeigen den Unterschied zwischen was auch immer Elemente new Liste hat, so dass die Ausgabe sollte wie folgt aussehen:Vergleichen Sie zwei Listen von Tupeln

Match  : ver = 1121 
Match  : sign = 89 
Mismatch : type = 01 (old : 00) 

Ich könnte alle passenden Tupel mit unten Liste Verständnis bekommen, aber konnte nicht darüber hinaus denken.

Bitte schlagen Sie mir einen Weg vor, es zu tun.

EDIT

Es tut mir leid für die nicht auf meine Frage ist klar, ich habe nicht eine Sache erwähnen, die Schlüssel in der Liste kann sich wiederholen, können die Liste bedeutet wie:

old = [('ver','1121'),('sign','89'),('address','A45'),('type','00'),('ver','sorry')] 

new = [('ver','1121'),('sign','89'),('type','01'),('ver','sorry)] 

UPDATE

Dank @holdenweb, ich habe seinen Code einige Änderungen vorgenommen und dies scheint die erwartete Ausgabe bereitstellt werden, schlagen Sie bitte, ob es irgendwelche Fehler.

old = [('ver','1121'),('sign','89'),('address','A45'),('type','00'),('ver','works?')] 
new = [('ver','1121'),('sign','89'),('type','01'),('ver','This')] 

formatter = "{:12}: {:8} = {}".format 
newfmter = "{} (old : {})".format 

kv_old = [] 
for i,(kn, vn) in enumerate(new): 
    vo = [(j,(ko,vo)) for j,(ko, vo) in enumerate(old) if (ko==kn) ] 
    for idx,(key,val) in vo: 
     if idx >=i: 
      kv_old = [key,val] 
      break; 

    if kv_old[1]==vn: 
     print(formatter("Match", kv_old[0], kv_old[1])) 
    else: 
     print(formatter("Mismatch", kn, newfmter(vn, kv_old[1]))) 
+3

was würde mit "Adresse" passieren? – MooingRawr

+0

Bitte schlagen Sie vor, wenn Sie eine andere Möglichkeit haben, die Listen zu durchlaufen, wenn sie nicht durch List-Comprehensions erreichbar sind. – Ron

+0

Da es nicht in beiden Listen ist, nichts @MooingRawr –

Antwort

0

Sie können wie etwas tun:

old = [('ver','1121'),('sign','89'),('address','A45'),('type','00')] 
new = [('ver','1121'),('sign','89'),('type','01')] 
my_list = [(a,b) for (a,b) in new for (c,d) in old if ((a==c) and (b==d))] 
for i in old: 
    if i in my_list: 
      print "Match : ", i 
    else: 
      print "Mismatch : ", i 

, die Ihnen:

Match : ('ver', '1121') 
Match : ('sign', '89') 
Mismatch : ('address', 'A45') 
Mismatch : ('type', '00') 

Aber sicher gibt es eine "pythonic" way ....

0

Hier ist ein One-Liner, um eine Liste aller Vergleiche zu erhalten. Je nachdem, wie groß Ihre alte und neue Listen sind, wäre ein Satz Verständnis ein wenig schneller arbeiten, aber diese Geschwindigkeit würde unten durch meinen sorted + itertools.groupby Ansatz zunichte gemacht werden (wie sorted ein list zurückgibt):

comps = [(key, 'changed', old_val, new_val) 
      if old_val != new_val else (key, 'same', old_val) 
      for key, old_val in old for oth_key, new_val in new 
      if key == oth_key] 

comps jetzt ist:

[('ver', 'same', '1121'), 
('sign', 'same', '89'), 
('type', 'changed', '00', '01')] 

drucken sie es aus:

for t in comps: 
    if len(t) == 3: 
     print('%s: %s, value: %s' % (t[1], t[0], t[2])) 
    else: 
     print('%s: %s, value: %s' % (t[1], t[0], ', '.join(t[2:]))) 

same: ver, value: 1121 
same: sign, value: 89 
changed: type, value: 00, 01 

Edit: Die Folgendes ist nicht genau das, was OP will, aber ich lasse es trotzdem für diejenigen, die daran interessiert sind zu sehen, was gleich geblieben ist und was sich als Zweites geändert hat (eigentlich könnte man eine benutzerdefinierte Grammatik definieren, nach der man die Elemente sehen möchte das änderte sich zuerst, aber das liegt an dir).

für vorbereiten itertools.groupby verwenden, und unter Wunsch des Konto OP für den Druckauftrag oben gezeigt, können wir ein collections.OrderedDict Objekt zu erstellen, verwenden effektiv ein „geordnete Menge“ von „Schlüssel“:

import collections 

proper_order = tuple(collections.OrderedDict.fromkeys([x[0] for x in new]).keys()) 

proper_order 
Out[43]: ('ver', 'sign', 'type') 

Jetzt sortieren comps basierend auf der benutzerdefinierten Grammatik in proper_order:

comps_sorted = sorted(comps, key=lambda x: proper_order.index(x[0])) 

comps_sorted 
Out[45]: 
[('ver', 'same', '1121'), 
('sign', 'same', '89'), 
('type', 'changed', '00', '01')] 

Verwenden itertools.groupby drucken:

for key, group in itertools.groupby(comps_sorted, key=lambda x: x[1]): 
    for g in group: 
     print('%s: %s' % (key, ', '.join(x for x in g if x not in ('same', 'changed')))) 

same: ver, 1121 
same: sign, 89 
changed: type, 00, 01 

Es ist einfach so, dass die Reihenfolge dieser Ausgabe die gleiche ist wie die oben angeforderte OP, aber für größere Fälle wird der Unterschied in der Reihenfolge zwischen den beiden Ansätzen offensichtlich.

+0

Was meinen Sie mit "Bestellung Angelegenheiten?" Du meinst du brauchst "gleich" bevor "verändert"? – blacksite

+0

@not_a_robot, funktioniert es, wenn ich Tasten in beiden Listen wiederholt habe? sagen, alte und neue Listen haben noch ein Tupel ('ver', 'blah') – Ron

+0

Bitte beachten Sie den aktualisierten Ansatz. – blacksite

1

Sie können ein verwenden set:

>>> old = [('ver','1121'),('sign','89'),('address','A45'),('type','00')] 
>>> new = [('ver','1121'),('sign','89'),('type','01')] 

>>> print('no longer there:', set(old) - set(new)) 
no longer there: {('type', '00'), ('address', 'A45')} 

>>> print('newly added:', set(new) - set(old)) 
newly added: {('type', '01')} 

>>> print('still there:', set(old) & set(new)) 
still there: {('sign', '89'), ('ver', '1121')} 
+0

'('type', '00')' ist nicht mehr da, aber '('type', '01')' wurde neu hinzugefügt. –

+1

es ist ein Werkzeug OP kann verwenden, um herauszufinden, die nicht übereinstimmen :) –

0

Was dazu:

n,o=dict(new),dict(old) 
for i in n: 
    print "{0:10}:{2:8} {3:8} {1}".format(*(("Match","") if o.get(i)==n[i] else ("Mismatch",o.get(i,i)))+ (i,n[i])) 

Ausgang:

Mismatch :type  01  00 
Match  :ver  1121  
Match  :sign  89  

Wenn Sie den Auftrag benötigen, versuchen OrderedDict zu verwenden:

from collections import OrderedDict 
n,o=OrderedDict(new),OrderedDict(old) 
1

Manchmal ist ein Listenverständnis nicht die Antwort. Dies könnte einer dieser Zeiten sein. Außerdem behandeln Sie nicht den Fall, in dem ein Schlüssel in old, aber nicht in new vorhanden ist - ich schließe diesen Fall hier ein, obwohl Sie diesen Code aushacken können, wenn es nicht relevant ist. Sie könnten ähnlich den Fall von Schlüsseln behandeln, die von new fehlen, aber ich bin so weit nicht gegangen.

old = [('ver','1121'),('sign','89'),('address','A45'),('type','00')] 
new = [('ver','1121'),('sign','89'),('type','01'),("sneaky", 'not there before')] 
formatter = "{:12}: {:8} = {}".format 
newfmter = "{} (old : {})".format 

for (kn, vn) in new: 
    if any(ko==kn for (ko, vo) in old): 
     ko, vo = [(ko, vo) for (ko, vo) in old if ko==kn][0] 
     if vo==vn: 
      print(formatter("Match", ko, vo)) 
     else: 
      print(formatter("Mismatch", kn, newfmter(vn, vo))) 
    else: 
     print(formatter("New", kn, vn)) 
+0

können wir die 'enumerate()' verwenden, um durch beide Listen zu durchlaufen, um die Wiederholungsschlüssel kümmern? – Ron

+0

'enumerate' weist den Elementen in einer Sequenz einfach Nummern zu, so dass ich nicht sicher bin, wie es helfen würde. Aber wenn die Listen groß werden, gibt es eine Reihe möglicher Tricks. Die erste, die mir in den Sinn kommt, besteht darin, für jede Liste ein Diktat zu erstellen, dessen Schlüssel die ersten Elemente der Tupel sind und deren Werte die Position dieses Tupels in der Liste sind. Das würde es viel schneller machen, das korrekte Listenelement zu bestimmen, ohne darüber zu iterieren (was eine O (n/2) -Operation ist). – holdenweb

Verwandte Themen