【问题标题】:Python intersection of 2 lists of dictionaries2个字典列表的Python交集
【发布时间】:2016-02-06 04:41:33
【问题描述】:

我有 2 个类似的字典列表

list1 = [{'count': 351, 'evt_datetime': datetime.datetime(2015, 10, 23, 8, 45), 'att_value': 'red'},
     {'count': 332, 'evt_datetime': datetime.datetime(2015, 10, 23, 8, 45), 'att_value': 'red'},
     {'count': 336, 'evt_datetime': datetime.datetime(2015, 10, 23, 8, 45), 'att_value': 'red'},
     {'count': 359, 'evt_datetime': datetime.datetime(2015, 10, 23, 8, 45), 'att_value': 'red'},
     {'count': 309, 'evt_datetime': datetime.datetime(2015, 10, 23, 8, 45), 'att_value': 'red'}]


list2 = [{'count': 359, 'evt_datetime': datetime.datetime(2015, 10, 23, 8, 45), 'att_value': 'red'},
     {'count': 351, 'evt_datetime': datetime.datetime(2015, 10, 23, 8, 45), 'att_value': 'red'},
     {'count': 381, 'evt_datetime': datetime.datetime(2015, 10, 22, 8, 45), 'att_value': 'red'}]

我正在尝试从两个列表中获取常见的字典。我想要的输出与字典的键和值完全匹配。

[{'count': 359, 'evt_datetime': datetime.datetime(2015, 10, 23, 8, 45), 'att_value': 'red'},
     {'count': 351, 'evt_datetime': datetime.datetime(2015, 10, 23, 8, 45), 'att_value': 'red'}]

这可以通过 python 本身有效地完成还是需要像 pandas 这样的 lib?

【问题讨论】:

    标签: python python-3.4


    【解决方案1】:

    使用列表理解:

    [x for x in list1 if x in list2]
    

    这会为您的数据返回此列表:

    [{'count': 351, 'evt_datetime': datetime.datetime(2015, 10, 23, 8, 45), 'att_value': 'red'}, {'count': 359, 'evt_datetime': datetime.datetime(2015, 10, 23, 8, 45), 'att_value': 'red'}]
    

    【讨论】:

    • 不错!我不希望这可以通过简单的列表理解来完成。奇迹般有效。谢谢
    • 比 for 循环好 1000 倍。谢谢。
    • 请参阅stackoverflow.com/a/33067553/1497139 中的评论:这是一个 O(n^2) 解决方案,而有些解决方案具有 O(n) - 这意味着对于 1000 个元素,此解决方案比最佳解决方案慢 1000 倍使用排序列表。
    • 如果列表没有预先排序,请参见下面的 O(n log n) 解决方案。
    【解决方案2】:

    下面的解决方案对于大型列表可能表现更好,但由于排序步骤可能还需要更多内存。

    交集可以通过定义的 sortKey 来完成,例如'count' 或字典的哈希将按照https://stackoverflow.com/a/60765557/1497139 的建议使用。该算法对两个列表进行排序并并行迭代,检查两个迭代器的三种可能状态:

    • 第一个迭代器落后于第二个迭代器 -> 推进第一个迭代器
    • 第二个迭代器落后于第一个迭代器 -> 推进第二个迭代器
    • 都在同一个位置 -> 找到了一个交集元素

    在给定的示例中,使用“count”字段作为 sortKey 与使用 dict 哈希作为键的结果相同。

    [{'count': 351, 'evt_datetime': datetime.datetime(2015, 10, 23, 8, 45), 'att_value': 'red'}, {'count': 359, 'evt_datetime': datetime.datetime(2015, 10, 23, 8, 45), 'att_value': 'red'}]
    [{'count': 351, 'evt_datetime': datetime.datetime(2015, 10, 23, 8, 45), 'att_value': 'red'}, {'count': 359, 'evt_datetime': datetime.datetime(2015, 10, 23, 8, 45), 'att_value': 'red'}]
    

    python 单元测试

    def testIntersection(self):
            '''
            test creating the intersection of a list of dictionaries
            '''
            list1 = [{'count': 351, 'evt_datetime': datetime.datetime(2015, 10, 23, 8, 45), 'att_value': 'red'},
             {'count': 332, 'evt_datetime': datetime.datetime(2015, 10, 23, 8, 45), 'att_value': 'red'},
             {'count': 336, 'evt_datetime': datetime.datetime(2015, 10, 23, 8, 45), 'att_value': 'red'},
             {'count': 359, 'evt_datetime': datetime.datetime(2015, 10, 23, 8, 45), 'att_value': 'red'},
             {'count': 309, 'evt_datetime': datetime.datetime(2015, 10, 23, 8, 45), 'att_value': 'red'}]
    
            list2 = [{'count': 359, 'evt_datetime': datetime.datetime(2015, 10, 23, 8, 45), 'att_value': 'red'},
                 {'count': 351, 'evt_datetime': datetime.datetime(2015, 10, 23, 8, 45), 'att_value': 'red'},
                 {'count': 381, 'evt_datetime': datetime.datetime(2015, 10, 22, 8, 45), 'att_value': 'red'}]
            
            listi=ListOfDict.intersect(list1, list2,'count')
            print(listi)
            self.assertEquals(2,len(listi))
            listi=ListOfDict.intersect(list1, list2)
            print(listi)
            self.assertEquals(2,len(listi))
    

    ListOfDict

    '''
    Created on 2020-08-11
    
    @author: wf
    '''
    
    class ListOfDict(object):
        '''
        https://stackoverflow.com/questions/33542997/python-intersection-of-2-lists-of-dictionaries/33543164
        '''
        @staticmethod  
        def sortKey(d,key=None):
            ''' get the sort key for the given dict d with the given key
            '''
            if key is None:
                # https://stackoverflow.com/a/60765557/1497139
                return hash(tuple(d.items()))
            else:
                return d[key] 
            
        @staticmethod            
        def intersect(listOfDict1,listOfDict2,key=None):
            '''
            get the  intersection lf the two lists of Dicts by the given key 
            '''
            i1=iter(sorted(listOfDict1, key=lambda k: ListOfDict.sortKey(k, key)))
            i2=iter(sorted(listOfDict2, key=lambda k: ListOfDict.sortKey(k, key)))
            c1=next(i1)
            c2=next(i2)
            lr=[]
            while True:
                try:
                    val1=ListOfDict.sortKey(c1,key)
                    val2=ListOfDict.sortKey(c2,key)
                    if val1<val2:
                        c1=next(i1)
                    elif val1>val2:
                        c2=next(i2)
                    else:
                        lr.append(c1)
                        c1=next(i1)
                        c2=next(i2)
                except StopIteration:
                    break     
            return lr  
    
    
        
    

    【讨论】:

      【解决方案3】:

      如果顺序不重要并且您不需要担心重复,那么您可以使用设置交集:

      a = [1,2,3,4,5]
      b = [1,3,5,6]
      list(set(a) & set(b))
      [1, 3, 5]
      

      【讨论】:

      • 是的,由于 dict() 。因为它们是不可散列的。我的错。
      • 字典不可散列,所以我的列表中的 set() 不起作用
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-06-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-25
      • 2015-10-29
      相关资源
      最近更新 更多