Ansible:替换字典值后如何去除嵌套列表结构
问题
我有以下两个字典:
"fictional_characters": { "male": [ "Donkey", "Humpty", "Piranha" ], "female": [ "Fiona", "Kitty_Softpaws", "Diane_Foxington" ] }
以及
"movie_names": { "Donkey": "Shrek", "Humpty": "Puss_in_Boots", "Piranha": "The_Bad_Guys", "Fiona": "Shrek", "Kitty_Softpaws": "Puss_in_Boots", "Diane_Foxingtin": "The_Bad_Guys" }
我想要把fictional_characters字典中的角色名替换为movie_names字典中对应的电影名,目标结构如下:
"fictional_characters": { "male": [ "Shrek", "Puss_in_Boots", "The_Bad_Guys" ], "female": [ "Shrek", "Puss_in_Boots", "The_Bad_Guys" ] }
我先将fictional_characters转换为列表:
- name: Convert fictional_characters to a list set_fact: fictional_characters_list: "{{fictional_characters | dict2items }}"
得到的结果为:
"fictional_characters_list": [ { "key": "male", "value": [ "Donkey", "Humpty", "Piranha" ] }, { "key": "female", "value": [ "Fiona", "Kitty_Softpaws", "Diane_Foxington" ] } ]
接着我用Jinja2模板进行值替换:
- name: Using Jinja to swap dict values set_fact: fict_char_movies: | {% for e in fictional_characters_list %} {{ e.key }}: {% for char in e.value %} {% if char in movie_names %} - {{ movie_names[char]|split(',') }} {% endif %} {% endfor %} {% endfor %} - name: Print the result debug: msg: "{{ fict_char_movies | from_yaml }}"
但返回的结果存在嵌套列表,不符合预期:
"male": [ [ "Shrek" ], [ "Puss_in_Boots" ], [ "The_Bad_Guys" ] ], "female": [ [ "Shrek" ], [ "Puss_in_Boots" ], [ "The_Bad_Guys" ] ]
请问如何修改代码去除嵌套列表,得到目标结构?
解决方法
出现嵌套列表的核心原因是使用了split(',')过滤器——movie_names中的电影名都是单个字符串,没有逗号分隔,split(',')会把单个字符串拆成仅含一个元素的列表,最终导致嵌套结构。
方法1:修改原Jinja2模板
直接去掉split(',')过滤器,输出原始电影名字符串即可,修改后的任务代码如下:
- name: Using Jinja to swap dict values set_fact: fict_char_movies: | {% for e in fictional_characters_list %} {{ e.key }}: {% for char in e.value %} {% if char in movie_names %} - {{ movie_names[char] }} {% endif %} {% endfor %} {% endfor %} - name: Print the result debug: msg: "{{ fict_char_movies | from_yaml }}"
方法2:更简洁的字典转换方式
无需先将字典转成列表,利用Ansible内置的过滤器可以一次性完成转换,代码更精简高效:
- name: Directly map characters to movies set_fact: fictional_characters_movies: >- {{ fictional_characters | dict2items | map('combine', { 'value': item.value | map('extract', movie_names) | list }) | items2dict }} - name: Print final result debug: var: fictional_characters_movies
该方法的逻辑:
- 用
dict2items将原字典转换为键值对列表 - 对每个键值对,通过
map('extract', movie_names)把角色列表映射为对应的电影名列表 - 用
combine更新每个键值对的value字段 - 最后通过
items2dict将处理后的键值对列表转回字典,直接得到目标结构
内容的提问来源于stack exchange,提问作者piercjs
相关产品推荐
相关产品推荐

