Yritän optimoida sisäkkäistä silmukoita varten, jotka vertaavat matriisin elementtiä matriisin loppuelementin kanssa .
Siellä on kaksi osaa, ensimmäinen osa on esimerkiksi taulukossa 3 elementtiä, ja kukin elementti on sanakirja:
[{"someKey_1":"a"}, {"someKey_1":"b"}, {"somekey_1":"a"}]
1. iterointi (1. elementti vertaa 2. elementtiin):
”someKey” -tunnusavain ”kahdelle elementille, koska a != b
, emme tee mitään
2. iterointi (1. elementti vertaa 3. elementtiin):
”SomeKey” -testiavain kahdelle elementille, koska a == a
, teemme logiikkaa
Koodi (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
Koodin #Some Logic -osa edellyttää avainten yhdistämistä sanakirjasta toiseen, esimerkiksi:
for key in val_2.keys(): val[key]=val_2[key]
Koodi:
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)
Näytesyöttö (set_of_pk_values):
Joten otospanoksen perusteella haluamme verrata, ovatko edeltäjät samat, jos ne ovat samat, ottakaamme nämä kaksi kuten esimerkiksi:
{"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"}
Koska heillä on samat edeltäjät, yhdistämme nämä kaksi sanakirjaa paitsi avaimen ”s”: käyttäjänimi, aika_merkki, setid_hash, setid, kunto (jos on) ),
{"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"}
Toinen osa on hyvin samanlainen kuin edellinen esimerkki (3 kohdetta luettelossa), samassa sanakirjassa on näppäimeen liittyvä taulukko (nyt on yksi sanakirja, jossa on kaksi avainta taulukon jokaisessa elementissä), sanotaan:
[{"someKey_1":[b,f]}{"someKey_2":a}, {"someKey_1":[e,f]}{"someKey_2":b}, {"somekey_1":[h,k]}{"someKey_2":c}]
1. iterointi (1. elementti vertaa 2. elementtiin):
silmukkaa taulukon läpi avaimella: someKey_1
b == b
(2. elementti ” s someKey_2), tee sitten logiikkaa
f != b
(2. elementti s someKey_2), logiikkaa ei tehdä
2nd iterointi (1. elementti vertaa 3. elementillä):
selaa taulukon läpi avaimella: someKey_1
b == c
(kolmas elementti s someKey_2), sitten tee logiikkaa
f != c
(kolmas elementti s someKey_2), logiikkaa ei tehdä
Koodi (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
Koodin #Some Logic -osa on sama kuin ensimmäinen sisäkkäinen silmukka, joka edellyttää avainten ja niiden arvojen yhdistämistä sanakirjasta toiseen. esimerkki:
for key in val_2.keys(): val[key]=val_2[key]
Koodi:
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)
Vastaavasti tämän pitäisi tehdä on vertailla edeltäjän taulukkoa setid_hashiin, jos ne ovat yhtä suuret, yhdistämme.
Koko koodi:
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)
Ensimmäisen sisäkkäisen silmukan käyttöaika on tällä hetkellä 21 sekuntia, ja toisen sisäkkäisen silmukan pituus on noin 19 sekuntia. Verrattuna muihin prosesseihin, jotka vaihtelevat välillä 0–1 sekuntia, tämä osa on selvästi pullonkaula.
Voiko kukaan osoittaa minua oikeaan suuntaan, kuinka optimoida tämä yksinkertainen, mutta erittäin aikaa vievä koodi?
Muokkaa:
Yritä tehdä ast.literal_eval ennen sisäkkäisiä silmukoita:
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
Vastaa
ast.literal_eval(...)
Jos voimme poistaa puhelusi numeroon ast.literal_eval(...)
meidän pitäisi nähdä, että silmukoiden ajoaika lyhenee mukavasti. Mutta miksi voimme poistaa tämän, mitä kysyt? Harkitse:
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
Kuten yllä olevasta katkelmasta näet, ast.literal_eval(...)
jäsentää ja arvioi välitetyn merkkijonon se ja palauta kyseisen merkkijonon kirjaimellinen esitys (olettaen tietysti, että merkkijono edustaa kelvollista literaalia). On selvää, että on tehokkaampaa verrata m
ja n
kuin verrata x
ja y
. Ei myöskään näytä siltä, että olet huolissasi siitä, onko val
vai val_2
kelvollinen python-literaali, koska skenaariossa ast.literal_eval(...)
heittää poikkeuksen, oletuksena verrata vain merkkijonoja, jotka getter(val)
ja getter(val_2)
. Pitkä tarina, voit poistaa try: / except:
ja käyttää vain lauseita, jotka sinulla on lausekkeen except
alla.
for key in val_2.keys()
Yllä oleva silmukka esiintyy molempien silmukoiden 1
ja 2
. Tarkista jokaisella iteraatiolla, että key
ei vastaa 7 muuta mahdollista avainarvoa. Kuusi näistä avainarvoista esiintyy esitetyissä tiedoissa ja seitsemäs (condition
) ei.Sen pitäisi olla tehokkaampaa korvata:
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]
sanoilla:
# 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]
Kommentit
- Minulla on kirjaimellinen merkkijonojen esitys sanakirjan avainarvoparin sisällä. Ajattelin sitä, että pystyin kirjoittamaan for for -silmukan, joka yrittää muuttaa avainta, arvoparia ensin. Sitten minun ei ’ tarvitse testata ast.literal_eval myöhemmin. Tämä nopeutui merkittävästi 20 sekunnista millisekunteihin.