2017-12-18 238 views
1

的嵌套列表我有字典的嵌套列表類似如下:高效篩選字典

list_of_dict = [ 
     { 
     "key": "key1", 
     "data": [ 
      { 
       "u_key": "u_key_1", 
       "value": "value_1" 
      }, 
      { 
       "u_key": "u_key_2", 
       "value": "value_2" 
      } 
     ] 
     }, 

     { 
     "key": "key2", 
     "data": [ 
      { 
       "u_key": "u_key_1", 
       "value": "value_3" 
      }, 
      { 
       "u_key": "u_key_2", 
       "value": "value_4" 
      } 
     ] 
     } 
    ] 

正如你可以看到list_of_dict是字典的列表,裏面的是,data也是字典的列表。假設list_of_dictdata內部的所有對象具有相似的結構,並且所有密鑰始終存在。

在接下來的步驟I轉換list_of_dictlist_of_tuples,其中元組的第一個元素是key隨後針對value密鑰的所有值內data

list_of_tuples = [ 
      ('key1', 'value_1'), 
      ('key1', 'value_2'), 
      ('key2', 'value_3'), 
      ('key2','value_4') 
] 

的最後一步是用一個列表(comparison_list)比較。列表包含string值。列表中的值可以來自value關鍵內部數據。我需要檢查comparison_list中的任何值是否在list_of_tuples之內,並獲取該值的鍵(第一個元組項)。

comparison_list = ['value_1', 'value_2'] 

我的預期輸出是:

out = ['key1', 'key1'] 

我的解決方案如下:

>>> list_of_tuples = [(c.get('key'),x.get('value')) 
       for c in list_of_dict for x in c.get('data')] 

    >>> for t in list_of_tuple: 
      if t[1] in comparison_list: 
       print("Found: {}".format(t[0])) 

所以問題總結是,我有我需要找到值(comparison_list)的列表在data陣列內。

我正在操作的數據集非常大(> 100M)。我期待加快我的解決方案並使其更加緊湊和可讀。 我能以某種方式跳過創建list_of_tuples並直接進行比較的步驟嗎?

+1

不知怎的,你的例子並不適合。你的意思是'(c.get('key'),x.get('value')'?無論如何,如果你想加快速度,可能是一個很好的'compare_list'設置' –

+0

@ tobias_k是的,我已經編輯了這個問題,我會嘗試設置謝謝:) –

+0

comparison_list = ['value_1','value_2']是您的預期輸出? –

回答

1

有幾個簡單的優化,你可以嘗試:

  • 使comparison_list一個set所以查找是O(1),而不是爲O(n)
  • 使list_of_tuples發電機,所以你不」噸有一次
  • 兌現所有的條目,您還可以在條件融入發電機本身

例子:

comparison_set = set(['value_1', 'value_2']) 
tuples_generator = ((c['key'], x['value']) 
        for c in list_of_dict for x in c['data'] 
        if x['value'] in comparison_set) 
print(*tuples_generator) 
# ('key1', 'value_1') ('key1', 'value_2') 

當然,你也可以保持比較獨立於發電機:

tuples_generator = ((c['key'], x['value']) 
        for c in list_of_dict for x in c['data']) 
for k, v in tuples_generator: 
    if v in comparison_set: 
     print(k, v) 

或者你可以,而不是從list_of_dicts創建comparison_set一個dict映射值的鍵。這可以更快地找到特定值的關鍵,但請注意,您只能爲每個值保留一個鍵。

values_dict = {x['value']: c['key'] 
       for c in list_of_dict for x in c['data'] 
       if x['value'] in comparison_set} 
print(values_dict) 
# {'value_2': 'key1', 'value_1': 'key1'} 
+0

有沒有辦法避免元組生成器的步驟,並直接與'list_of_dict'比較? –

+0

@GarbageCollector你是什麼意思?那會是什麼樣的預期結果? 'tuple_generator'不應該造成太大的傷害,它基本上只是一個迭代器的懶惰評估指令。 –

+0

是的,我知道使用發電機是一個非常好的主意。但是,如果您在問題結束時看到我發佈的解決方案,則有兩個步驟。爲'compare_list'中的匹配項生成元組列表和文件鍵。我想跳過元組生成並直接進行比較。 –

1

在最後一步,你可以使用過濾器這樣的事情,而不是循環訪問指出:

comparison_list = ['value_1', 'value_2'] 

print(list(filter(lambda x:x[1] in comparison_list,list_of_tuples))) 

輸出:

[('key1', 'value_1'), ('key1', 'value_2')] 
+0

當你說「沒有循環」,這聽起來好像這不需要循環,但它仍然在'list'和'map'內。 list_of_dict]中x的x.get('data')]中的列表理解'[[(x.get('key'),g.get('value'))不僅更容易解析對於一個人來說),但也幾乎快兩倍。 –

+0

@tobias_k我知道,但你知道內置和本地範圍?內置的語言是用'c'語言編寫的,當你使用循環的本地作用域循環時,搜索它。 –

+0

我想我是這樣做的;那它呢?你說「內建函數是用C語言實現的」,所以'%timeit'對我說謊時,列表的理解速度更快?另外,爲什麼不直接將參數直接放入您的答案中,而不是「google it」? –