You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Ansible将两个列表转换为扁平化聚合字典的实现方法

Ansible Jinja2 实现指定IP列表到reg分组映射方案

需求说明

重发说明:无法编辑之前的提问,修正后的核心需求为:将指定IP列表转换为键为reg标识、值为对应IP数组的反转映射字典,最终结果仅允许包含IPs列表内指定的IP,不得纳入列表外条目。

输入结构

初始输入数据格式:

IPs: [ 'ip1', 'ip2', 'ip3' ]
DICT: { 'ip1': 'reg1', 'ip2': 'reg2', 'ip3': 'reg2', 'ip4': 'reg3', ... } 

前期已通过过滤器提取两个简化处理用的列表:

list1: {{ DICT | dict2items() | selectattr('key', 'in', IPs) | list | map(attribute='value') | list }}
list2: {{ DICT | dict2items() | selectattr('key', 'in', IPs) | list | map(attribute='key') | list }}

提取后列表值:

list1: [ 'reg1', 'reg2', 'reg2' ]
list2: [ 'ip1', 'ip2', 'ip3']

期望输出

两种格式均符合要求:

  • 格式1(单IP为字符串、多IP为数组):
{ 'reg1': 'ip1', 'reg2': [ 'ip2', 'ip3' ] }
  • 格式2(所有值统一为数组,更推荐):
{ 'reg1': [ 'ip1' ], 'reg2': [ 'ip2', 'ip3' ] }

已尝试方案的问题

  • 直接zip转字典:使用{{ dict(list1 | zip(list2) | list }}转换时,重复reg键会被覆盖,仅保留首个对应IP,输出为{ 'reg1': 'ip1', 'reg2': 'ip2' },无法自动聚合同reg下的多个IP。
  • 分组后直接转字典:使用{{ dict(dict(list2 | zip(list1)) | dict2items() | groupby(attribute='value') | list ) }}时,输出值为完整的key/value字典项列表,未提取纯IP值,错误输出如下:
{ 'reg2': [{'key': 'ip2', 'value': 'reg2'}, {'key': 'ip3', 'value': 'reg2'}], 'reg1': [{'key': 'ip1', 'value': 'reg1'}] }

验证场景

测试输入

IPs: [ 'ip1', 'ip2' ]
DICT: { 'ip1': 'reg1', 'ip2': 'reg2', 'ip3': 'reg2', 'ip4': 'reg3', ... } 

期望输出

{ 'reg1': [ 'ip1' ], 'reg2': [ 'ip2' ] }

已有方案缺陷

@Vladimir-Botka 提供的方案逻辑顺序错误,未对IP范围做二次过滤,会直接读取原DICT中同reg下的所有IP,包含不在指定IP列表内的条目,实现代码如下:

arr: "{{ DICT|dict2items|groupby('value') }}"
keys: "{{ arr|map('first')|list }}"
vals: "{{ arr|map('last')|map('map', attribute='key')|list }}"
var1: "{{ dict(keys|zip(vals)) }}"
regs: "{{ IPs|map('extract', DICT) }}"
var2: "{{ var1|dict2items|selectattr('key','in', regs)|items2dict }}"

该方案在上述验证场景下会错误输出{ 'reg1': [ 'ip1' ], 'reg2': [ 'ip2' , 'ip3' ] },将不在IP列表内的ip3也纳入结果,不符合需求。


正确实现方案

之前方案出错的核心原因是处理顺序颠倒:先对全量DICT按reg分组,再筛选目标reg,会把同reg下不在指定IP列表的条目也带入结果。正确逻辑必须先过滤IP范围,再对筛选后的结果按reg值分组,实现代码如下:

# 输出统一数组格式(推荐,后续遍历、判断逻辑更简单)
ip_reg_map: "{{ dict(
  DICT | dict2items
  | selectattr('key', 'in', IPs)
  | groupby('value')
  | map('zip', ['reg_key', 'ip_list'])
  | map('map', 'last')
  | map('zip', [[], ['key']])
  | map('map', 'map')
  | map('map', 'last')
) }}"

如果需要单IP返回字符串、多IP返回数组的格式,在上述结果基础上增加一步转换即可:

ip_reg_map_fmt: "{{ dict(
  ip_reg_map | dict2items
  | map(attribute='key')
  | zip(
      ip_reg_map | dict2items
      | map(attribute='value')
      | map('first' if (item | length == 1) else item)
    )
) }}"

结果验证

  • 针对第一组输入IPs: ['ip1','ip2','ip3'],输出为{'reg1': ['ip1'], 'reg2': ['ip2', 'ip3']},符合预期。
  • 针对第二组验证输入IPs: ['ip1','ip2'],输出为{'reg1': ['ip1'], 'reg2': ['ip2']},不会引入不在列表内的ip3,结果正确。

内容的提问来源于stack exchange,提问作者Mister Bullyster

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 01:01:42