有两个这样的字典列表,如何按字典的 key 值进行去重合并? 比较高效率的做法?

2020-02-26 19:37:01 +08:00
 qazwsxkevin

请教思路算法,或者用什么轮子会更高效?
毕竟整个 List 还是挺大的,7 到 8 万个元素,
今天试着用 for,for,for 来整,不太成功,而且解决思路线径还把自己绕晕了
后来想着是放入 Mysql 搞的,但考虑到使用环境,不太现实
今天试着用 pandas 来弄了一下,结果还把自己弄晕在 index 和 row 的事情上了

   AList = [{'型号': 12, '重量': 16, '产地': 19,'审核人':33},
            {'型号': 22, '重量': 92, '产地': 87,'审核人':34},
            {'型号': 15, '重量': 27, '产地': 86,'审核人':35},
            {'型号': 71, '重量': 55, '产地': 21,'审核人':36}]

   BList = [{'产地': 87, '型号': 22, '重量': 92,'审核人':34},
            {'产地': 86, '型号': 15, '重量': 27,'审核人':35},
            {'产地': 44, '型号': 65, '重量': 91,'审核人':33}]
A,B 两个列表每个元素都是一个字典  
A,B 两个 List 选择性进行合并,得出 CList  

例子是只有四个 k/v 对, 但实际字典很多 k/v 对,而且每个字典里面的键值对的数量,也不尽相同  

合并有以下去重条件:  
只以型号, 重量, 审核人三个 value 作为去重判断,  
A,B 两个列表,如果有这三个 value 重复, 只保留 AList 内容(整个字典)加入到 CList  
BList 里面字典里三个 value 不重复的,整个字典作为元素加入到 CList
4282 次点击
所在节点    Python
15 条回复
1373569162
2020-02-26 20:20:36 +08:00
构造一个 dict,型号, 重量, 审核人拼接起来作为 key,遍历两个 list,key 不在 dict 里就加进去,最后输出 dict.values()
epicnoob
2020-02-26 22:24:09 +08:00
f = lambda _: (_['产地'], _['型号'], _['重量'])
t = sorted(AList+BList, key=f)
CList = reduce(lambda l, v: l + [v] if f(l[-1]) != f(v) else l, t, [t[0]])
epicnoob
2020-02-26 22:25:03 +08:00
排序是稳定的,相同值肯定是 Alist 的在前面
ferstar
2020-02-26 22:50:52 +08:00
python >= 3.6

```python3
a_list = [
{"型号": 12, "重量": 16, "产地": 19, "审核人": 33},
{"型号": 22, "重量": 92, "产地": 87, "审核人": 34},
{"型号": 15, "重量": 27, "产地": 86, "审核人": 35},
{"型号": 71, "重量": 55, "产地": 21, "审核人": 36},
]

b_list = [
{"产地": 87, "型号": 22, "重量": 92, "审核人": 34},
{"产地": 86, "型号": 15, "重量": 27, "审核人": 35},
{"产地": 44, "型号": 65, "重量": 91, "审核人": 33},
]


def generate_key(item):
return "_".join(v for k, v in item.items() if k != "型号")


hash_map = {}

for item in a_list:
hash_map.setdefault(generate_key(item), item)

for item in b_list:
hash_map.setdefault(generate_key(item), item)

c_list = list(hash_map.values())
```
MoYi123
2020-02-26 22:57:20 +08:00
tmp = set()
rt = []
for i in AList + BList:
t = (i['型号'], i['重量'], i['审核人'])
if t not in tmp:
tmp.add(t)
rt.append(i)
ferstar
2020-02-26 23:05:45 +08:00
bugmakerxs
2020-02-26 23:12:58 +08:00
就用 mysql 啊
bugmakerxs
2020-02-26 23:16:11 +08:00
型号+重量+产地 md5 做 key,该行数据为 value 放入一个字典,Blist 先放进去,alist 后放进去。或者直接做张标,key 做唯一索引
BlackBerry999
2020-02-27 08:34:11 +08:00
构建一个 3 层的多叉树,一层型号,二层重量,三层审核人。然后遍历 AB 两个 list 构建 3 层多叉树,并且来自于 AList 的值可以覆盖重写叶子节点。
wuwukai007
2020-02-27 10:54:29 +08:00
逻辑梳理一下,
第一、A 与 B 找固定那三个列的重复,重复的值只保留 原 A 的,保存到 c
第二,B 根据三列去重后,并且不在刚刚第一步 的结果中 保存到 c
第三、A 根据三列去重,保存到 c
wuwukai007
2020-02-27 11:19:45 +08:00
regex = ['型号','审核人','重量']
d1 = pd.DataFrame(a_list).drop_duplicates(regex)
d2 = pd.DataFrame(b_list).drop_duplicates(regex)
buf = d1.merge(d2,on=regex,how='inner')
new_col = [col for col in buf.columns.tolist() if str(col).endswith('_x')] + regex
buf_c = buf[new_col]
buf_c.columns = [str(col).replace('_x','') for col in buf_c.columns.tolist()]
c1 = d1.append(buf_c).drop_duplicates(regex).to_dict(orient="records")
c2 = d2.to_dict('records')
c_list = c1 + c2
wuwukai007
2020-02-27 11:43:21 +08:00
还有我试了下 几万条数据 就算用纯 for 循环写,也不慢的吧。
MisterLee
2020-02-27 17:29:49 +08:00
——Python&Pandas

a_df= pd.DataFrame(a_list)
b_df= pd.DataFrame(b_list)

a_b_df = pd.concat([a_df, b_df], axis=0).drop_duplicates(['型号', '重量', '审核人'], keep='first')

c_list = []

for _, item in a_b_df.iterrows():
c_list.append(item.dropna().to_dict())
wdc63
2020-02-27 18:35:39 +08:00
@bugmakerxs 嗯,遍历列表 A,以型号, 重量, 审核人的值做 key,下标做 value,建立 hash 表,遍历列表 B,查找每一个元素是否在 hash 表中,有的话合并到 Alist,没有的话添加到 Alist 末尾,每个字典都很简单,合并过程复杂度可以认为是 O(1),整个算法复杂度为 O(M+N),应该是效率最高的算法了。
moxiaowei
2020-03-04 10:53:27 +08:00
@wdc63 确实是的

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/647801

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX