2017-12-18 239 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”? –