Ik “probeer een genest te optimaliseren voor lussen die een element in de array vergelijkt met de rest van het element in de array .
Er is twee delen, het eerste deel is bijvoorbeeld een array met 3 elementen, en elk element is een woordenboek:
[{"someKey_1":"a"}, {"someKey_1":"b"}, {"somekey_1":"a"}]
1e iteratie (1e element is vergelijkbaar met 2e element):
Testsleutel van “someKey “voor twee elementen, sinds a != b
, dan doen we niets
2e iteratie (1e element is vergelijkbaar met 3e element):
Test sleutel van “someKey” voor twee elementen, aangezien a == a
, doen we wat logica
De code (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
Het #Some Logic-gedeelte van de code vereist het combineren van sleutels van het ene woordenboek naar het andere, bijvoorbeeld:
for key in val_2.keys(): val[key]=val_2[key]
De code:
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)
Voorbeeldinvoer (set_of_pk_values):
Dus op basis van de voorbeeldinvoer willen we vergelijken of voorgangers hetzelfde zijn, als ze hetzelfde zijn, laten we deze twee als voorbeeld nemen:
{"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"}
Aangezien ze dezelfde voorgangers hebben, zullen we deze twee woordenboeken combineren, behalve de sleutel “s: gebruikersnaam, time_string, setid_hash, setid, condition (indien aanwezig ),
{"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"}
Het tweede deel lijkt sterk op het vorige voorbeeld (3 items in de lijst), in hetzelfde woordenboek hebben we een array geassocieerd met een sleutel (nu is er een enkel woordenboek met twee sleutels in elk element van de array), laten we zeggen:
[{"someKey_1":[b,f]}{"someKey_2":a}, {"someKey_1":[e,f]}{"someKey_2":b}, {"somekey_1":[h,k]}{"someKey_2":c}]
1e iteratie (1e element vergeleken met 2e element):
doorloopt de array met de sleutel: someKey_1
b == b
(2e element ” s someKey_2), doe dan wat logica
f != b
(2e element “s someKey_2), er wordt geen logica gedaan
2e iteratie (1e element vergelijken s met 3e element):
doorloopt de array met de sleutel: someKey_1
b == c
(3e element “s someKey_2), dan doe wat logica
f != c
(3rd element “s someKey_2), er wordt geen logica gedaan
De code (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
Het #Some Logic-gedeelte van de code is hetzelfde als de eerste geneste lus, waarvoor het combineren van sleutels en hun waarden van het ene woordenboek naar het andere vereist is. voorbeeld:
for key in val_2.keys(): val[key]=val_2[key]
De code:
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)
Evenzo wat dit zou moeten doen is het vergelijken van de array van voorganger met setid_hash, als ze gelijk zijn, dan combineren we.
Volledige code:
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)
Momenteel is de looptijd voor de eerste geneste lus 21 seconden, en de tweede geneste lus is ongeveer 19 seconden. Vergeleken met andere processen, variërend van 0-1 seconden, is dit deel duidelijk een bottleneck.
Kan iemand me in de juiste richting wijzen om dit stukje eenvoudige, maar extreem tijdrovende code te optimaliseren?
Bewerken:
Probeer een ast.literal_eval uit te voeren voor geneste lussen:
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
Answer
ast.literal_eval(...)
Als we uw oproepen naar we zouden een mooie vermindering van de looptijd van je loops moeten zien. Maar waarom kunnen we dit verwijderen, vraagt u zich af? Overweeg:
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
Zoals je kunt zien in het bovenstaande fragment, ast.literal_eval(...)
zal elke string die je doorgeeft, analyseren en evalueren it, en retourneer een letterlijke weergave van die tekenreeks (uiteraard aangenomen dat de tekenreeks een geldige letterlijke waarde vertegenwoordigt). Het is duidelijk dat het efficiënter is om m
en n
te vergelijken dan om x
te vergelijken en y
. Het lijkt er ook niet op dat u zich zorgen maakt of val
of val_2
een geldige letterlijke Python is, omdat in het scenario dat ast.literal_eval(...)
genereert een uitzondering, u vergelijkt standaard alleen de strings die worden geretourneerd door getter(val)
en getter(val_2)
. Om een lang verhaal kort te maken, je kunt de try: / except:
verwijderen en gewoon de uitspraken gebruiken die je hebt onder de except
-clausule.
for key in val_2.keys()
De bovenstaande lus treedt op als de binnenste lus van beide lussen 1
en 2
. Bij elke iteratie controleer je of key
niet gelijk is aan 7 andere mogelijke sleutelwaarden. 6 van deze sleutelwaarden komen voor in de gegevens die je hebt gepresenteerd en de 7e (condition
) niet.Het zou efficiënter moeten zijn om:
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]
te vervangen door:
# 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]
Reacties
- Ik heb een letterlijke weergave van strings die binnen het sleutelwaardepaar van het woordenboek stonden. Toen ik daarover nadacht, was ik in staat om een for-lus te schrijven die eerst probeert het sleutel- en waardepaar te veranderen. Dan hoef ik ‘ niet later op ast.literal_eval te testen. Dit had een aanzienlijke versnelling, van 20 seconden tot milliseconden.