En rad ordböcker; jämföra varje {nyckel, värde} par; och kombinera ordböcker

Jag försöker optimera en kapslad för loopar som jämför ett element i arrayen med resten av elementet i matrisen .

Det finns två delar, den första delen är till exempel, en array har 3 element och varje element är en ordlista:

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

1: a iteration (1: a element jämförs med 2: a element):

Testnyckel för ”someKey ”för två element, eftersom a != b, gör vi ingenting


2: a iteration (första elementet jämförs med 3: e elementet):

Testnyckel för ”someKey” för två element, eftersom a == a, gör vi lite logik


Koden (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 

#Some Logic-delen av koden kräver att tangenter kombineras från en ordlista till en annan, till exempel:

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

Koden:

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) 

Provingång (set_of_pk_values):

Så baserat på provingången är vad vi vill göra att jämföra om föregångarna är desamma, om de är desamma, låt oss ta dessa två som till exempel:

{"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"} 

Eftersom de har samma föregångare kommer vi att kombinera dessa två ordböcker utom nyckelns: användarnamn, tidssträng, setid_hash, setid, villkor (om det finns ),

 {"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"} 

Den andra delen är väldigt lik föregående exempel (3 objekt i listan), i samma ordlista har vi en array associerat med en nyckel (nu finns det en enda ordlista med två nycklar i varje element i arrayen), låt oss säga:

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

1: a iteration (1: a element jämförs med 2: a element):

slingrar genom matrisen med nyckeln: someKey_1

b == b (2: a element ” s someKey_2), gör sedan lite logik

f != b (2: a element ”s someKey_2), ingen logik är klar


2nd iteration (första elementet jämför s med tredje element):

slingrar genom matrisen med nyckeln: someKey_1

b == c (3: e elementet är someKey_2), sedan gör lite logik

f != c (3: e elementet är someKey_2), ingen logik är klar


Koden (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 

#Some Logic-delen av koden är densamma som den första kapslade slingan, som kräver att tangenter och deras värden kombineras från en ordbok till en annan, för exempel:

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

Koden:

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) 

På samma sätt vad detta ska göra är jämförelsen av föregångarens array med setid_hash, om de är lika, kombinerar vi dem.


Fullständig kod:

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) 


För närvarande är körtiden för den första kapslade slingan: 21 sekunder och den andra kapslade slingan är cirka 19 sekunder. Jämfört med andra processer, som sträcker sig från 0-1 sekunder, är denna del helt klart en flaskhals.

Kan någon peka mig i rätt riktning för hur man optimerar den här enkla, men extremt tidskrävande koden?


Redigera:

Försök att göra en ast.literal_eval före kapslade loopar:

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 

Svara

ast.literal_eval(...)

Om vi kan ta bort dina samtal till ast.literal_eval(...) vi borde se en bra minskning av dina slingors körtid. Men varför kan vi ta bort detta, frågar du? Överväg:

 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 

Som du kan se från kodavsnittet ovan kommer ast.literal_eval(...) att analysera och utvärdera vilken sträng du passerar det, och returnera en bokstavlig representation av den strängen (förutsätter naturligtvis att strängen representerar en giltig bokstav). Det är uppenbart att det är effektivare att jämföra m och n än att jämföra x och y. Det verkar inte heller som om du är orolig för om val eller val_2 är en giltig pythonbokstavlig för under scenariot att ast.literal_eval(...) ger ett undantag, du jämför som standard bara strängarna som returneras av getter(val) och getter(val_2) Lång historia kort du kan ta bort try: / except: och bara använda uttalandena du har under except -satsen.

for key in val_2.keys()

Ovanstående slinga uppträder som den inre slingan för båda slingorna 1 och 2. För varje iteration kontrollerar du att key inte motsvarar sju andra möjliga nyckelvärden. 6 av dessa nyckelvärden förekommer i de data du har presenterat och den sjunde (condition) inte ”t.Det borde vara effektivare att ersätta:

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] 

med:

# 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] 

Kommentarer

  • Jag har en bokstavlig representation av strängar som var inne i ordboks nyckelvärde. Med tanke på det kunde jag skriva en for-loop som försöker ändra nyckel, värdepar först. Då behöver jag inte ’ testa för ast.literal_eval senare. Detta hade betydande fart, från 20 sekunder till millisekunder.

Lämna ett svar

Din e-postadress kommer inte publiceras. Obligatoriska fält är märkta *