Ansible合并字典列表:将同name项的net字段合并为列表
Ansible字典列表分组合并:按name+region合并net字段
需求说明
现有如下字典列表:
result: [ { "name": "DC1", "region": "EU", "net": "10.10.1.0" }, { "name": "DC1", "region": "EU", "net": "10.10.2.0" }, { "name": "DC2", "region": "NA", "net": "10.10.3.0" } ]
需要将其转换为:合并所有name和region相同的项,对应net字段合并为列表;若该分组仅单个项,net保留字符串格式:
[ { "name": "DC1", "region": "EU", "net": ["10.10.1.0","10.10.2.0"] }, { "name": "DC2", "region": "NA", "net": "10.10.3.0" } ]
原方法问题分析
你之前的Playbook逻辑错误:
- 第一步用
dict2items拆分每个字典为键值对列表,拼接后得到所有键值对的集合 - 第二步循环去重后的键值对,生成单个键的小字典
这种方式完全没有实现按name+region分组合并的核心逻辑,只是把所有键值对拆分散开,因此得到的结果不符合预期。
正确解决方案
利用Ansible的groupby过滤器实现分组,再对每个分组做合并处理,完整Playbook如下:
- hosts: localhost vars: result: [ { "name": "DC1", "region": "EU", "net": "10.10.1.0" }, { "name": "DC1", "region": "EU", "net": "10.10.2.0" }, { "name": "DC2", "region": "NA", "net": "10.10.3.0" } ] tasks: - name: 按name和region组合分组 set_fact: grouped_dcs: "{{ result | groupby(item => [item.name, item.region]) }}" - name: 生成合并后的最终列表 set_fact: merged_result: "{{ merged_result | default([]) + [ { 'name': group_key[0], 'region': group_key[1], 'net': net_list | length == 1 | ternary(net_list[0], net_list) } ] }}" loop: "{{ grouped_dcs }}" vars: group_key: "{{ item.0 }}" group_items: "{{ item.1 }}" net_list: "{{ group_items | map(attribute='net') | list }}" - name: 输出结果 debug: var: merged_result
步骤解释
- 分组:使用
groupby(item => [item.name, item.region])将原列表按name和region的组合作为分组键,得到的grouped_dcs是一个列表,每个元素格式为(分组键列表, 该组的字典列表),比如(["DC1", "EU"], [{}, {}])。 - 合并分组:循环每个分组:
- 从分组键中提取
name和region - 用
map(attribute='net')收集该组所有net值并转为列表 - 通过
ternary过滤器判断:若net列表长度为1,保留字符串格式;否则保留列表格式
- 从分组键中提取
- 拼接结果:将每个分组处理后的字典拼接到最终列表
merged_result中。
执行结果
运行上述Playbook后,merged_result将完全符合预期格式:
merged_result: - name: DC1 region: EU net: - 10.10.1.0 - 10.10.2.0 - name: DC2 region: NA net: 10.10.3.0
内容的提问来源于stack exchange,提问作者Marek
相关产品推荐
相关产品推荐

