基于单一非唯一键合并两个字典列表

2 投票
3 回答
1460 浏览
提问于 2025-04-17 07:24

我有两个字典列表,比如:

l1 = [{"customer":"amy", "order":2}, {"customer":"amy", "order":3}, {"customer":"basil", "order":4}]
l2 = [{"customer":"amy", "died":"who fell down the stairs"}, {"customer":'basil', "died":"assaulted by bears"}]

我想找个优雅的方法,把第二个列表(l2)里的键放到第一个列表(l1)里。这是为了把使用不同值作为索引的字典列表合并在一起。

这个函数应该像这样:join(l1, l2, 'customer'),然后生成

l3 = [{"customer":"amy", "order":2,"died":"who fell down the stairs"}, {"customer":"amy", "order":3,"died":"who fell down the stairs"}, {"customer":"basil", "order":4,"died":"assaulted by bears"}}]

l3应该为l1中的每个字典都生成一个字典。

如果l1和l2在非连接键上有相同的值但不同的内容,l2的值会优先。

l2会有连接键的唯一值。

现在我试过这段不太好看的代码:

l3 = []
rdict = {}
for i in range(len(l2)):
    rdict[l2[i][field]]=i
for d in l1: 
    l3.append(dict(d.items()+l2[rdict[d[field]]].items()))
return l3

还有 这个SO问题的解决方案,但那个假设所有列表中只有一个索引。

谢谢

3 个回答

0
l3= [{"id": 64, "attribute1": 2},
     {"id": 62, "attribute1": 3}, 
     {"id": 64, "attribute2": 3}]

l4 = [{"id": 64, "Energy1": 2},
     {"id": 62, "Energy1": 3}, 
     {"id": 64, "Energy2": 3}]



def m1(l1,l2):
    l1d = {}
    for dct in l1: l1d.setdefault(dct["id"], {}).update(dct)
    l2d = {}
    for dct in l2: l2d.setdefault(dct["id"], {}).update(dct)
    aa = {
        k : dict(l1d.get(k,{}),**v) for k,v in l2d.items()
        
        }
    aal = [*aa.values()]
    aalp = print(aal)
    return aalp        
m1(l3, l4)    

"""
Output :
[{'id': 64, 'attribute1': 2, 'attribute2': 3, 'Energy1': 2, 'Energy2': 3}, {'id': 62, 'attribute1': 3, 'Energy1': 3}]

"""

解释:

  1. 这段代码接收两个字典列表,然后把它们合并成一个字典列表。

  2. 代码首先从这两个字典列表中创建两个字典。

  3. 这些字典是通过把id当作键,其他的内容当作值来创建的。

  4. 接着,代码用id作为键,合并后的字典作为值,创建一个新的字典。

  5. 然后,代码从这个新字典中生成一个列表。

  6. 接下来,代码打印出这个列表。

  7. 最后,代码返回这个列表。

最好的方法是使用defaultdict(dict)

方法2(最佳):

from _collections import defaultdict
from operator import itemgetter


    l1 = [{"id":1, "b":2}, 
          {"id":2, "b":3},
          {"id":3, "b":"10"},
          {"id":4, "b":"7"}]
    
    l2 = [{"id":1, "c":4},
          {"id":2, "c":5},
          {"id":6, "c":8},
          {"id":7, "c":9}]
    
    
    def m2(l1,l2):
        d = defaultdict(dict)
        for l in (l1,l2):
            for innerdict in l :
                d[innerdict['id']].update(innerdict)
        dv = d.values()
        dvsorted = sorted(d.values(),key= itemgetter('id'))
        dvsorted1 = [*dvsorted]
        dvsorted1_print = print(dvsorted1)
        return dvsorted1_print
    
    m2(l1, l2)
            
    """
    Output :
    
    [{'id': 1, 'b': 2, 'c': 4}, {'id': 2, 'b': 3, 'c': 5}, {'id': 3, 'b': '10'}, {'id': 4, 'b': '7'}, {'id': 6, 'c': 8}, {'id': 7, 'c': 9}]
    
    """

解释:

  1. 这段代码接收两个字典列表作为输入,并返回一个字典列表。

  2. 代码使用defaultdict来创建一个字典的字典。

  3. 代码使用update来更新内部的字典。

  4. 代码使用itemgetter来对字典列表进行排序。

  5. 代码使用*来解包字典列表。

  6. 打印出字典列表。

1

另一种答案...

def diff(d1, d2, key):
    if d1[key] != d2[key]:
        return d1
    new_keys = list(set(d2) - set(d1))
    for new_key in new_keys:
        d1[new_key] = d2[new_key]
    return d1

def join(l1, l2, key):
    l3 = l1
    for d2 in l2:
        l3 = map(lambda d1: diff(d1, d2, key), l3)
    return l3
3

简单:

SELECT *
FROM l1, l2
WHERE l1.customer = l2.customer

...开个玩笑...

def join(t1,t2,column):
    result = []
    for entry in t2:
        for match in [d for d in t1 if d[column] == entry[column]]:
            result.append(dict((k,v) for k,v in entry.items()+match.items()))
    return result

撰写回答