一連の辞書。各{キー、値}ペアを比較します。辞書を組み合わせる

配列内の要素を比較するネストされたforループを最適化しようとしています配列内の残りの要素とともに

2つの部分があります。最初の部分は、たとえば、配列には3つの要素があり、それぞれが要素は辞書です:

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

最初の反復(最初の要素は2番目の要素と比較されます):

“someKeyのテストキー”2つの要素の場合、a != bなので、何もしません


2回目の反復(1番目の要素と3番目の要素の比較):

2つの要素の「someKey」のキーをテストします。a == aなので、いくつかのロジックを実行します


コード(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 

コードの#SomeLogic部分では、たとえば、ある辞書から別の辞書にキーを組み合わせる必要があります。

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

コード:

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) 

サンプル入力(set_of_pk_values):

サンプル入力に基づいて、前任者が同じであるかどうかを比較します。前任者が同じである場合は、次の2つを例に挙げてみましょう。

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

前任者が同じであるため、キーを除いてこれら2つの辞書を組み合わせます:username、time_string、setid_hash、setid、condition(存在する場合) )、

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


2番目の部分は前の例(リスト内の3つの項目)と非常によく似ており、同じ辞書にキーに関連付けられた配列(配列の各要素に2つのキーを持つ単一の辞書があります)。たとえば、次のようになります。

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

1回目の反復(1番目の要素は2番目の要素と比較):

次のキーを使用して配列をループします:someKey_1

b == b(2番目の要素 ” ■someKey_2)、次にいくつかのロジックを実行します

f != b(2番目の要素のsomeKey_2)、ロジックは実行されません


2番目反復(最初の要素の比較sと3番目の要素):

次のキーを使用して配列をループします:someKey_1

b == c(3番目の要素のsomeKey_2)、次にいくつかのロジックを実行します

f != c(3番目の要素のsomeKey_2)、ロジックは実行されません


コード(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 

コードの#SomeLogic部分は、最初のネストされたループと同じであり、キーとその値を1つの辞書から別の辞書に組み合わせる必要があります。例:

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

コード:

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) 

同様にこれが行うことになっていることは、先行の配列をsetid_hashと比較します。それらが等しい場合は、結合します。


完全なコード:

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) 

現在、最初のネストされたループの実行時間は21秒で、2番目のネストされたループは約19秒です。 0〜1秒の範囲の他のプロセスと比較すると、この部分は明らかにボトルネックです。

この単純でありながら非常に時間のかかるコードを最適化する方法について、誰かが正しい方向を示すことができますか?


編集:

ネストされたループの前にast.literal_evalを実行してみてください:

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 

回答

ast.literal_eval(...)

ループの実行時間が大幅に短縮されるはずです。しかし、なぜ私たちはあなたが尋ねるこれを取り除くことができますか?考えてみてください:

 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 

上記のスニペットからわかるように、ast.literal_eval(...)は渡された文字列を解析して評価しますそして、その文字列のリテラル表現を返します(もちろん、文字列が有効なリテラルを表すと仮定します)。明らかに、mnを比較する方が、xを比較するよりも効率的です。およびy。また、valまたはval_2が有効なPythonリテラルであるかどうかについては、次のようなシナリオでは懸念されていないようです。 ast.literal_eval(...)は例外をスローします。デフォルトでは、getter(val)getter(val_2)によって返された文字列を比較するだけです。簡単に言うと、try: / except:を削除して、except句の下にあるステートメントを使用するだけです。

for key in val_2.keys()

上記のループは、11の両方のループの最も内側のループとして発生します。 div id = “6350f65165”>

。反復ごとに、keyが他の7つの可能なキー値と同等ではないことを確認します。これらの重要な値のうち6つは、提示したデータで発生し、7つ目(condition)は発生しません。次のように置き換える方が効率的です:

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] 

次のように:

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

コメント

  • 辞書のキーと値のペアの中にある文字列のリテラル表現があります。 そのことを考えると、最初にキーと値のペアを変更しようとするforループを作成することができました。 その後、’後でast.literal_evalをテストする必要はありません。 これにより、20秒からミリ秒に大幅に高速化されました。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です