2012-01-29 12 views
5

Ho due elenchi di risultati del test. I risultati del test sono rappresentati come dizionari:Confronto degli elenchi di dizionari

list1 = [{testclass='classname', testname='testname', testtime='...},...] 
list2 = [{testclass='classname', testname='testname', ...},...] 

La rappresentazione dizionario è leggermente diverso in entrambe le liste, perché per una lista Ho qualche ulteriori informazioni. Ma in tutti i casi, ogni dizionario di test in entrambi gli elenchi avrà un nome di classe e un elemento testname che insieme formano un modo efficace per identificare in modo univoco il test e un modo per confrontarlo tra gli elenchi.

Ho bisogno di capire tutti i test che sono in list1 ma non in list2, in quanto rappresentano nuovi fallimenti di test.

Per fare questo che faccio:

def get_new_failures(list1, list2): 
    new_failures = [] 
    for test1 in list1: 
     for test2 in list2: 
      if test1['classname'] == test2['classname'] and \ 
        test1['testname'] == test2['testname']: 
       break; # Not new breakout of inner loop 
     # Doesn't match anything must be new 
     new_failures.append(test1); 
    return new_failures; 

mi chiedo è un modo più pitone di fare questo. Ho guardato i filtri. La funzione utilizzata dal filtro dovrebbe avere un handle per entrambe le liste. Uno è facile, ma non sono sicuro di come otterrebbe un vantaggio per entrambi. Conosco il contenuto degli elenchi fino al runtime.

Qualsiasi aiuto sarebbe apprezzato,

Grazie.

+0

errori di battitura @Wooble fissati – dublintech

risposta

8

Prova questo:

def get_new_failures(list1, list2): 
    check = set([(d['classname'], d['testname']) for d in list2]) 
    return [d for d in list1 if (d['classname'], d['testname']) not in check] 
+1

+1, questo è stato il pensiero successivo che ho avuto - non ho notato che l'hai pubblicato. – senderle

2

Se ciascuna combinazione di classname e testname è veramente unica, l'approccio più efficiente dal punto di vista del calcolo sarebbe utilizzare due dizionari anziché due elenchi. Come chiave del dizionario, utilizzare una tupla in questo modo: (classname, testname). Quindi puoi semplicemente dire if (classname, testname) in d: ....

Se è necessario conservare l'ordine di inserimento e si sta utilizzando Python 2.7 o versioni successive, è possibile utilizzare uno OrderedDict dal modulo collections.

Il codice dovrebbe essere simile a questa:

tests1 = {('classname', 'testname'):{'testclass':'classname', 
            'testname':'testname',...}, 
     ...} 
tests2 = {('classname', 'testname'):{'testclass':'classname', 
            'testname':'testname',...}, 
     ...} 

new_failures = [t for t in tests1 if t not in tests2] 

Se è necessario utilizzare gli elenchi per qualche motivo, si potrebbe iterare list2 per generare un insieme, e poi prova per l'appartenenza a quel set:

test1_tuples = ((d['classname'], d['testname']) for d in test1) 
test2_tuples = set((d['classname'], d['testname']) for d in test2) 
new_failures = [t for t in test1_tuples if t not in test2_tuples] 
+0

il codice di grandi opere, ma ha un errore di battitura nel test2_tuples = ... '' linea - una parentesi manca –

+0

@ ÓscarLópez, anzi, grazie ! Risolto ora. – senderle

2

per confrontare due dict d1 e d2 su un sottoinsieme delle loro chiavi, uso:

all(d1[k] == d2[k] for k in ('testclass', 'testname')) 

E se i due elenchi hanno la stessa lunghezza, è possibile utilizzare zip() per accoppiarli.

+3

Ma questo richiede ancora iterazioni sul prodotto cartesiano delle due liste ... – senderle

+0

@senderle: se ha due liste, non vedo il problema in questo. –

Problemi correlati