O serie de dicționare; compararea fiecărei perechi {cheie, valoare}; și combinarea dicționarelor

Încerc să optimizez un imbricat pentru bucle care compară un element din matrice cu restul elementului din matrice .

Există două părți, prima parte este, de exemplu, o matrice are 3 elemente și fiecare elementul este un dicționar:

[{"someKey_1":"a"}, {"someKey_1":"b"}, {"somekey_1":"a"}] 

Prima iterație (primul element se compară cu al doilea element):

Cheia de testare a „someKey „pentru două elemente, deoarece a != b, atunci nu facem nimic


a doua iterație (primul element se compară cu al 3-lea element):

Cheia de testare a „someKey” pentru două elemente, deoarece a == a, facem o logică


Codul (Sudo):

for idx, first_dictionary in enumerate(set_of_pk_values): for second_dictionary in (set_of_pk_values[idx+1:]): if (first_dictionary["someKey"] == second_dictionary["someKey"]): #Some Logic 

Partea #Some Logic a codului necesită combinarea cheilor dintr-un dicționar în altul, de exemplu:

for key in val_2.keys(): val[key]=val_2[key] 

Codul:

newList = [] skipList = [] checked = [] getter = itemgetter("predecessor") getter_2 = itemgetter("setid_hash") for idx, val in enumerate(set_of_pk_values): if(idx not in skipList): for val_2 in set_of_pk_values[idx+1:]: if(idx not in checked): try: if (ast.literal_eval(getter(val)) == ast.literal_eval(getter(val_2))): for key in val_2.keys(): if(key != "block" and key != "username" and key != "setid" and key != "setid_hash" and key != "predecessor" and key != "time_string" and key != "condition"): val[key]=val_2[key] skipList.append(idx) except: if (getter(val) == getter(val_2)): for key in val_2.keys(): if(key != "block" and key != "username" and key != "setid" and key != "setid_hash" and key != "predecessor" and key != "time_string" and key != "condition"): val[key]=val_2[key] skipList.append(idx) checked.append(idx) 

Intrare eșantion (set_of_pk_values):

Deci, pe baza eșantionului de intrare, ceea ce vrem să facem este să comparăm dacă predecesorii sunt aceiași, dacă sunt aceiași, să luăm aceste două ca de exemplu:

{"username": u"radcad", "predecessor": u"[u"6a5e4bc9a328c1aeb52c565b675e6141", u"818428a59215e75d76111c8ca29a314d", u"6c acfc059508f8cb716ad0126f001f84"]", "time_string": u"2014/06/26@07:02:40", "S.clpe_leafcell.UTC_Post_start": u"1403766190", "setid_hash": u"14443f7238927d6e95 befbe12ecc6dd0", "setid": u"1986068", "block": u"simple_buff"} {"username": u"radcad", "predecessor": u"[u"6a5e4bc9a328c1aeb52c565b675e6141", u"818428a59215e75d76111c8ca29a314d", u"6c acfc059508f8cb716ad0126f001f84"]", "S.rcxt_maxcl.Predecessors": u"clpe_leafcell", "time_string": u"2015/03/08@03:06:26", "setid_hash": u"ffce9f0c46f3459acbba4f0ced884f3a", "setid": u"3095862", "block": u"simple_buff"} 

Deoarece au aceiași predecesori, vom combina aceste două dicționare, cu excepția cheii „s: nume de utilizator, șir de timp, setid_hash, setid, condiție (dacă există) ),

 {"username": u"radcad", "predecessor": u"[u"6a5e4bc9a328c1aeb52c565b675e6141", u"818428a59215e75d76111c8ca29a314d", u"6c acfc059508f8cb716ad0126f001f84"]", "time_string": u"2014/06/26@07:02:40", "S.clpe_leafcell.UTC_Post_start": u"1403766190", "S.rcxt_maxcl.Predecessors": u"clpe_leafcell", "setid_hash": u"14443f7238927d6e95 befbe12ecc6dd0", "setid": u"1986068", "block": u"simple_buff"} 

A doua parte este foarte asemănătoare cu exemplul anterior (3 elemente din listă), în același dicționar, avem un matricea asociată cu o cheie (acum există un dicționar unic cu două chei în fiecare element al matricei), să spunem:

[{"someKey_1":[b,f]}{"someKey_2":a}, {"someKey_1":[e,f]}{"someKey_2":b}, {"somekey_1":[h,k]}{"someKey_2":c}] 

Prima iterație (primul element se compară cu al doilea element):

parcurge matricea cu cheia: someKey_1

b == b (al doilea element ” s someKey_2), apoi faceți ceva logic

f != b (al doilea element „s someKey_2), nu se face logică


2nd iterație (compararea elementului 1 s cu al treilea element):

parcurge matricea cu cheia: someKey_1

b == c (al treilea element este someKey_2), apoi faceți o logică

f != c (al 3-lea element este oarecare Cheie_2), nu se face logică


Codul (Sudo):

for idx, val in enumerate(set_of_pk_values): for idx_2, val_2 in enumerate(set_of_pk_values): for pred in val["someKey_1"]: if(val_2["someKey_2"] == pred): #Some Logic 

Partea #Some Logic a codului este aceeași cu prima buclă imbricată, care necesită combinarea tastelor și a valorilor acestora dintr-un dicționar în altul, pentru exemplu:

for key in val_2.keys(): val[key]=val_2[key] 

Codul:

newList = [] skipList = [] checked = [] getter = itemgetter("predecessor") getter_2 = itemgetter("setid_hash") for idx, val in enumerate(set_of_pk_values): if(idx not in skipList): for idx_2, val_2 in enumerate(set_of_pk_values): if(idx != idx_2): try: for pred in ast.literal_eval(getter(val)): if(getter_2(val_2) == pred): for key in val_2.keys(): if(key != "block" and key != "username" and key != "setid" and key != "setid_hash" and key != "predecessor" and key != "time_string" and key != "condition"): val[key]=val_2[key] skipList.append(idx_2) except: for pred in getter(val): if(getter_2(val_2) == pred): for key in val_2.keys(): if(key != "block" and key != "username" and key != "setid" and key != "setid_hash" and key != "predecessor" and key != "time_string" and key != "condition"): val[key]=val_2[key] skipList.append(idx_2) 

În mod similar, ceea ce ar trebui să facă este compararea matricei predecesorului cu setid_hash, dacă sunt egali, atunci combinăm.


Cod complet:

def test(): set_of_pk_values = [] cache = chartCache.objects.get(username_chartNum="Test 3_leimax", openedConfig="chartTable_774164170") data = chartCache_Data.objects.filter(ID = cache) max_value = data.aggregate(Max("counter"))["counter__max"] if(max_value != None): if(max_value != 0): cached = True for i in xrange(0, max_value+1): newItem = {} set_of_pk_values.append(newItem) for items in data.iterator(): set_of_pk_values[items.counter][str(items.key)] = items.value newList = [] skipList = [] checked = [] getter = itemgetter("predecessor") getter_2 = itemgetter("setid_hash") print str(len(set_of_pk_values)) timeNow = datetime.datetime.now() ############################################## #First Nested For Loop ############################################## for idx, val in enumerate(set_of_pk_values): if(idx not in skipList): for val_2 in set_of_pk_values[idx+1:]: if(idx not in checked): try: if (ast.literal_eval(getter(val)) == ast.literal_eval(getter(val_2))): for key in val_2.keys(): if(key != "block" and key != "username" and key != "setid" and key != "setid_hash" and key != "predecessor" and key != "time_string" and key != "condition"): val[key]=val_2[key] skipList.append(idx) except: if (getter(val) == getter(val_2)): for key in val_2.keys(): if(key != "block" and key != "username" and key != "setid" and key != "setid_hash" and key != "predecessor" and key != "time_string" and key != "condition"): val[key]=val_2[key] skipList.append(idx) checked.append(idx) ############################################## #Second Nested For Loop ############################################## for idx, val in enumerate(set_of_pk_values): if(idx not in skipList): for idx_2, val_2 in enumerate(set_of_pk_values): if(idx != idx_2): try: for pred in ast.literal_eval(getter(val)): if(getter_2(val_2) == pred): for key in val_2.keys(): if(key != "block" and key != "username" and key != "setid" and key != "setid_hash" and key != "predecessor" and key != "time_string" and key != "condition"): val[key]=val_2[key] skipList.append(idx_2) except: for pred in getter(val): if(getter_2(val_2) == pred): for key in val_2.keys(): if(key != "block" and key != "username" and key != "setid" and key != "setid_hash" and key != "predecessor" and key != "time_string" and key != "condition"): val[key]=val_2[key] skipList.append(idx_2) for idx, val in enumerate(set_of_pk_values): if(idx not in skipList): newList.append(val) set_of_pk_values = newList print str(len(set_of_pk_values)) timeEnd = datetime.datetime.now() print str(timeEnd - timeNow) 


În prezent, timpul de execuție pentru prima buclă imbricată: 21 de secunde, iar a doua buclă imbricată este de aproximativ 19 secunde. Comparativ cu alte procese, cuprinse între 0-1 secunde, această parte este în mod clar un blocaj.

Poate cineva să mă indice spre direcția corectă cu privire la modul de optimizare a acestei bucăți de cod simplu, dar care consumă mult timp?


Editați:

Încercați să faceți un ast.literal_eval înainte de bucle imbricate:

for items in set_of_pk_values: for key in item.keys(): getter = itemgetter(key) try: toChange = ast.literal_eval(getter(items)) items[key] = toChange except: pass 

Răspuns

ast.literal_eval(...)

Dacă putem elimina apelurile către ast.literal_eval(...) ar trebui să vedem o reducere drăguță a timpului de rulare al buclelor dvs. Dar, de ce putem elimina acest lucru pe care îl întrebați? Luați în considerare:

 m = "[0, 1, 2, ... , 9,999]" # a str representation of list w/ 10k elements, 0-9999 n = "[0, 1, 2]" x = ast.literal.eval(m) y = ast.literal.eval(n) x == range(10000) # true 

După cum puteți vedea din fragmentul de mai sus, ast.literal_eval(...) va analiza și evalua orice șir treceți și returnează o reprezentare literală a acelui șir (presupunând, desigur, că șirul reprezintă un literal valid). În mod clar, este mai eficient să comparați m și n decât să comparați x și y. De asemenea, nu pare că vă preocupă dacă val sau val_2 este un literal Python valid, deoarece în scenariul care ast.literal_eval(...) lansează o excepție, implicit comparând doar șirurile returnate de getter(val) și getter(val_2) . Pe scurt, puteți elimina try: / except: și utilizați doar afirmațiile pe care le aveți în clauza except.

for key in val_2.keys()

Bucla de mai sus apare ca bucla cea mai interioară a ambelor bucle 1 și 2. Cu fiecare iterație verificați dacă key nu este echivalent cu alte 7 valori cheie posibile. 6 dintre aceste valori cheie apar în datele pe care le-ați prezentat, iar a 7-a (condition) nu.Ar trebui să fie mai eficient să înlocuiți:

for key in val_2.keys(): if(key != "block" and key != "username" and key != "setid" and key != "setid_hash" and key != "predecessor" and key != "time_string" and key != "condition"): val[key]=val_2[key] 

cu:

# put this at the top of the test function x_keys = set(["block", "username", "setid", "setid_hash", "predecessor", "time_string", "condition"]) # ... for key in set(val_2.keys()) - x_keys: val[key] = val_2[key] 

Comentarii

  • Am o reprezentare literală a șirurilor care se afla în perechea de valori cheie a dicționarului. Gândindu-mă la asta, am reușit să scriu o buclă for care încearcă mai întâi să schimbe cheia, perechea de valori. Apoi nu ‘ nu trebuie să testez ast.literal_eval mai târziu. Aceasta a avut o accelerare semnificativă, de la 20 de secunde la milisecunde.

Lasă un răspuns

Adresa ta de email nu va fi publicată. Câmpurile obligatorii sunt marcate cu *