英文:
Return updated unsorted dict in Ansible
问题
我正在尝试合并一些字典,并保留它们各自位置上的项目,就像在Python中使用dict.update()
一样工作,但在Ansible中遇到了一些问题。
例如,我有两个字典:
dict1:
c_value: None
dict2:
b_value: None
a_value: None
我想要合并它们并保留顺序:
dict3:
c_value: None
b_value: None
a_value: None
我尝试了两种解决方案,使用Jinja2和Ansible过滤器combine
。它们在Jinja2在线编辑器中都正常工作,但如果我在Ansible中使用它们 - 调试显示我已按键名排序了字典:
dict3:
a_value: None
b_value: None
c_value: None
Jinja2模板:{%-set _ = dict1.update(dict2) -%}{{- dict1 -}}
Ansible combine:dict1 | combine(dict2)
英文:
I am trying to merge some dicts with saving their items on their own places like it is working in python using dict.update()
, but i have some troubles with it in Ansible.
For example, I have two dicts:
dict1:
c_value: None
dict2:
b_value: None
a_value: None
I want to merge them with saving order:
dict3:
c_value: None
b_value: None
a_value: None
I have tried 2 solutions, using jinja2 and ansible filter combine. All of them works fine in jinja2 online editors, but if i use it in ansible - debugging shows that I have sorted dict by key name:
dict3:
a_value: None
b_value: None
c_value: None
Jinja2 template: {%-set _ = dict1.update(dict2) -%}{{- dict1 -}}
Ansible combine: dict1 | combine(dict2)
答案1
得分: 1
以下是翻译好的部分:
字典,又称为 映射,在 YAML 中定义如下:
> "一个无序的键/值节点对的集合,..."
换句话说,在 YAML 中,字典的键没有固定的顺序。你看到的可能是 Python 3.7+ 的行为:
> "现在字典按照变量定义的词法顺序显示。之前,顺序是未定义的。"
查看 Ansible 使用的 Python 版本(在控制节点上执行):
shell> ansible --version
ansible [core 2.14.3]
...
python version = 3.9.17 (main, Jun 6 2023, 20:11:04) [GCC 9.4.0] (/usr/bin/python3.9)
jinja version = 3.1.2
libyaml = True
给定以下字典:
dict1:
c_value: None
dict2:
b_value: None
a_value: None
将它们合并:
dict3: "{{ dict1|combine(dict2) }}"
- 在 Python 3.7+ 中,键按词法顺序排序:
- debug:
msg: |
{{ dict3 }}
输出:
msg:
a_value: None
b_value: None
c_value: None
- 如果你想要其他顺序的键,可以这样声明。例如:
- debug:
msg: |
{% for k in key_order %}
{{ k }}: {{ dict3[k] }}
{% endfor %}
vars:
key_order: [c_value, b_value, a_value]
输出:
msg: |-
c_value: None
b_value: None
a_value: None
- 但是,如果你将文本转换为 YAML,则会再次得到排序后的键:
- debug:
msg: |
{% filter from_yaml %}
{% for k in key_order %}
{{ k }}: {{ dict3[k] }}
{% endfor %}
{% endfilter %}
vars:
key_order: [c_value, b_value, a_value]
输出:
msg:
a_value: None
b_value: None
c_value: None
<hr>
<sup>
用于测试的完整 playbook 示例:
- hosts: localhost
vars:
dict1:
c_value: None
dict2:
b_value: None
a_value: None
dict3: "{{ dict1|combine(dict2) }}"
tasks:
- debug:
msg: |
{{ dict3 }}
- debug:
msg: |
{% for k in key_order %}
{{ k }}: {{ dict3[k] }}
{% endfor %}
vars:
key_order: [c_value, b_value, a_value]
- debug:
msg: |
{% filter from_yaml %}
{% for k in key_order %}
{{ k }}: {{ dict3[k] }}
{% endfor %}
{% endfilter %}
vars:
key_order: [c_value, b_value, a_value]
英文:
A dictionary aka mapping is:
> "an unordered set of key/value node pairs, ..."
In other words, in YAML, there is no order in the dictionary's keys. What you see is probably Python 3.7+:
> "A dictionary now displays in the lexical order that variables were defined. Previously, the order was undefined."
See what Python your version of Ansible uses (on the controller)
shell> ansible --version
ansible [core 2.14.3]
...
python version = 3.9.17 (main, Jun 6 2023, 20:11:04) [GCC 9.4.0] (/usr/bin/python3.9)
jinja version = 3.1.2
libyaml = True
Given the dictionaries
dict1:
c_value: None
dict2:
b_value: None
a_value: None
combine them
dict3: "{{ dict1|combine(dict2) }}"
- The keys are ordered lexicographically by Python 3.7+
- debug:
msg: |
{{ dict3 }}
gives
msg:
a_value: None
b_value: None
c_value: None
- You have to declare another order of keys if you want to. For example,
- debug:
msg: |
{% for k in key_order %}
{{ k }}: {{ dict3[k] }}
{% endfor %}
vars:
key_order: [c_value, b_value, a_value]
gives
msg: |-
c_value: None
b_value: None
a_value: None
- But, if you convert the text to YAML you get the ordered keys again
- debug:
msg: |
{% filter from_yaml %}
{% for k in key_order %}
{{ k }}: {{ dict3[k] }}
{% endfor %}
{% endfilter %}
vars:
key_order: [c_value, b_value, a_value]
gives
msg:
a_value: None
b_value: None
c_value: None
<hr>
<sup>
Example of a complete playbook for testing
- hosts: localhost
vars:
dict1:
c_value: None
dict2:
b_value: None
a_value: None
dict3: "{{ dict1|combine(dict2) }}"
tasks:
- debug:
msg: |
{{ dict3 }}
- debug:
msg: |
{% for k in key_order %}
{{ k }}: {{ dict3[k] }}
{% endfor %}
vars:
key_order: [c_value, b_value, a_value]
- debug:
msg: |
{% filter from_yaml %}
{% for k in key_order %}
{{ k }}: {{ dict3[k] }}
{% endfor %}
{% endfilter %}
vars:
key_order: [c_value, b_value, a_value]
</sup>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论