Jessaie doptimiser une boucle for imbriquée qui compare un élément du tableau avec le reste de lélément dans le tableau .
Il y a deux parties, la première partie est par exemple, un Array a 3 éléments, et chacun lélément est un dictionnaire:
[{"someKey_1":"a"}, {"someKey_1":"b"}, {"somekey_1":"a"}]
1ère itération (le 1er élément se compare au 2ème élément):
Clé de test de « someKey « pour deux éléments, puisque a != b
, alors nous ne faisons rien
2ème itération (1er élément se compare au 3ème élément):
Test clé de « someKey » pour deux éléments, puisque a == a
, on fait un peu de logique
Le 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
La partie #Some Logic du code nécessite de combiner les clés dun dictionnaire à un autre, par exemple:
for key in val_2.keys(): val[key]=val_2[key]
Le 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)
Exemple dentrée (set_of_pk_values):
Donc, sur la base de lexemple dentrée, ce que nous voulons faire est de comparer si les prédécesseurs sont les mêmes, sils sont identiques, prenons ces deux comme par exemple:
{"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"}
Comme ils ont les mêmes prédécesseurs, nous allons combiner ces deux dictionnaires à lexception de la clé « s: username, time_string, setid_hash, setid, condition (sil existe ),
{"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"}
La deuxième partie est très similaire à lexemple précédent (3 éléments dans la liste), dans le même dictionnaire, nous avons un tableau associé à une clé (il existe maintenant « un dictionnaire unique avec deux clés dans chaque élément du tableau), disons:
[{"someKey_1":[b,f]}{"someKey_2":a}, {"someKey_1":[e,f]}{"someKey_2":b}, {"somekey_1":[h,k]}{"someKey_2":c}]
1ère itération (le 1er élément se compare au 2ème élément):
parcourt le tableau avec la clé: someKey_1
b == b
(2nd element » s someKey_2), puis fais de la logique
f != b
(2nd element « s someKey_2), aucune logique nest faite
2ème itération (1er élément comparer s avec le 3e élément):
parcourt le tableau avec la clé: someKey_1
b == c
(3e élément « s someKey_2), puis faire de la logique
f != c
(le 3ème élément « s someKey_2), aucune logique nest faite
Le 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
La partie #Some Logic du code est la même que la première boucle imbriquée, qui nécessite de combiner les clés et leurs valeurs dun dictionnaire à un autre, pour exemple:
for key in val_2.keys(): val[key]=val_2[key]
Le 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)
De même, ce que cela est censé faire est la comparaison du tableau du prédécesseur avec setid_hash, sils sont égaux, alors nous combinons.
Code 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)
Actuellement, le temps dexécution de la première boucle imbriquée: 21 secondes, et la deuxième boucle imbriquée est denviron 19 secondes. Par rapport à dautres processus, allant de 0 à 1 seconde, cette partie est clairement un goulot détranglement.
Quelquun peut-il mindiquer la bonne direction pour optimiser ce morceau de code simple mais extrêmement chronophage?
Modifier:
Essayez de faire un ast.literal_eval avant les boucles imbriquées:
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éponse
ast.literal_eval(...)
Si nous pouvons supprimer vos appels à ast.literal_eval(...)
nous devrions voir une belle réduction du temps dexécution de vos boucles. Mais pourquoi pouvons-nous supprimer ce que vous demandez? Considérez:
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
Comme vous pouvez le voir dans lextrait ci-dessus, ast.literal_eval(...)
analysera et évaluera la chaîne que vous passerez it et renvoie une représentation littérale de cette chaîne (en supposant bien sûr que la chaîne représente un littéral valide). De toute évidence, il est plus efficace de comparer m
et n
que de comparer x
et y
. De plus, il ne semble pas que vous vous préoccupiez de savoir si val
ou val_2
est un littéral python valide car dans le scénario qui ast.literal_eval(...)
lève une exception, vous comparez par défaut simplement les chaînes renvoyées par getter(val)
et getter(val_2)
. En bref, vous pouvez supprimer la try: / except:
et utiliser simplement les instructions que vous avez sous la clause except
.
for key in val_2.keys()
La boucle ci-dessus se produit comme la boucle la plus interne des deux boucles 1
et 2
. À chaque itération, vous vérifiez que key
nest pas « t équivalent à 7 autres valeurs de clé possibles. Six de ces valeurs clés se trouvent dans les données que vous avez présentées et la 7e (condition
) ne le fait pas.Il devrait être plus efficace de remplacer:
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]
par:
# 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]
Commentaires
- Jai une représentation littérale des chaînes qui se trouvaient à lintérieur de la paire clé-valeur du dictionnaire. En y réfléchissant, jai pu écrire une boucle for qui essaie de changer la paire clé / valeur en premier. Ensuite, je nai pas ‘ besoin de tester ast.literal_eval plus tard. Cela a eu une accélération significative, de 20 secondes à millisecondes.