【问题标题】:Fastest way to search common elements between 2 list of dictionaries in Python在 Python 中的 2 个字典列表之间搜索公共元素的最快方法
【发布时间】:2017-07-10 13:21:04
【问题描述】:

我有 2 个字典列表。

list1 = [{'user_id':23, 'user_name':'John', 'age':30},
         {'user_id':24, 'user_name':'Shaun', 'age':31},
         {'user_id':25, 'user_name':'Johny', 'age':32}]

list2 =[{'user_id':23},
        {'user_id':25}]

现在我想要输出

list3 = [{'user_id':23, 'user_name':'John', 'age':30},
         {'user_id':25, 'user_name':'Johny','age':32}]

我想要最有效的方法,因为我的list1 可能包含数百万行。

【问题讨论】:

  • 您是否尝试了一些不够快的方法?
  • 你看到thisthis。他们还不够快吗?您是否尝试实现此功能并遇到性能问题?
  • 如果你只需要对list1进行一次扫描,那么你应该使用Jean-François Fabre的策略。但是,如果您需要多次搜索,那么您应该认真考虑将列表转换为字典,按照 omri_saadon 的回答。如果您使用元组或命名元组,而不是为这个新字典的内部项目使用字典,它会节省 RAM。

标签: python


【解决方案1】:

您必须稍微转换list2 才能快速查找。我会用它制作一个set

list1 = [{'user_id':23, 'user_name':'John','age':30},
         {'user_id':24, 'user_name':'Shaun','age':31},
         {'user_id':25, 'user_name':'Johny','age':32}]

list2 =[{'user_id':23},
        {'user_id':25}]

list2_ids = {d['user_id'] for d in list2}

然后使用过滤列表理解构建list3。在那种情况下,in list2_ids 非常快,因为它使用来自set 的查找而不是线性搜索:

list3 = [x for x in list1 if x['user_id'] in list2_ids]

print(list3)

结果:

[{'user_id': 23, 'user_name': 'John', 'age': 30}, {'user_id': 25, 'user_name': 'Johny', 'age': 32}]

【讨论】:

    【解决方案2】:

    当键是 user_id 并且值是 nameage 时,我会将您的 list1 转换为字典。

    现在,当你查看这个dict 时,即使dict 有很多元素,复杂度也是O(1),用于查找。

    在这种情况下,查找所有用户 ID 的整个复杂性是 O(len(list2))

    dict1 = {23 : {'user_name':'John', 'age':30},
             24 : {'user_name':'Shaun', 'age':31},
             25 : {'user_name':'Johny', 'age':32}}
    
    list2 =[{'user_id':23},
            {'user_id':25}]
    
    res = [dict1.get(user['user_id']) for user in list2 if user['user_id'] in dict1]
    
    print (res)
    
    >>> [{'user_name': 'John', 'age': 30}, {'user_name': 'Johny', 'age': 32}]
    

    【讨论】:

    • 要再次转换我的list1,我需要迭代整个list1 对。这本身就增加了复杂性。
    • @curiousguy,你需要做一次。之后,您就拥有了这个数据结构,您可以在 O(1) 复杂度的情况下对其进行大量搜索。
    • 是的,我同意你的看法,搜索该格式非常快。问题是我的list1list2 根据输入不断变化。因此我必须每次都这样做。
    • @curiousguy ,你不能像上面的结构那样即时构建list1 吗?你不是控制它的人吗?
    • 还可以查看@PM 2Ring 评论。当您需要进行多次搜索时,此解决方案很好。如果只需要搜索一次,Jean-François Fabre 的解决方案更合适。
    【解决方案3】:

    就像之前的海报所说,您需要从列表 2 中创建一个 ID 列表:

    list2_ids = {d['user_id'] for d in list2}
    

    完成此操作后,还可以使用过滤功能:

    filter(lambda x: x['user_id'] in list2_ids, list1)
    

    虽然没有优化,但它的好处是有多个并行计算实现(如果您正在处理大量数据,您可能需要这些实现。

    也就是说,性能方面的最佳解决方案可能是设置交集 (comparison):

    unique_ids = set([d['user_id'] for d in list1]) & set([d['user_id'] for d in list2])
    list3 = [x for x in list1 if x['user_id'] in unique_ids]
    

    如果您确定列表不包含重复项,则可以忽略 set

    【讨论】:

      【解决方案4】:

      您可以使用 pandas 将数据框合并到一起。
      1. 将字典转换为数据框
      2. 合并“user_id”上的两个数据框

      import pandas as pd
      list1 = [{'user_id':23, 'user_name':'John', 'age':30},
                {'user_id':24, 'user_name':'Shaun', 'age':31},
                {'user_id':25, 'user_name':'Johny', 'age':32}] 
      list2 =[{'user_id':23},
               {'user_id':25}] 
      df1 = pd.DataFrame(list1)
      df1
         age  user_id user_name
      0   30       23      John
      1   31       24     Shaun
      2   32       25     Johny
      df2 = pd.DataFrame(list2)
      df2
         user_id
      0       23
      1       25
      
      pd.merge(df2,df1,on='user_id')
         user_id  age user_name
      0       23   30      John
      1       25   32     Johny
      

      【讨论】:

      • 其实我这里是避开熊猫。
      猜你喜欢
      • 2020-10-24
      • 1970-01-01
      • 2013-05-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-25
      • 1970-01-01
      • 2018-08-24
      相关资源
      最近更新 更多