使用列表构建字典/哈希



我正在尝试构建字典,但无法掌握 jinja2 如何插值变量。

我想将数组中的特定项目(例如 item[0])设置为特定的键值字典项目。

- set_fact: 
nodes: 
- node1
- node2 
- set_fact:
list_one: 
- f-one
- f-two 
- set_fact: 
list_two:
- n-one
- n-two

我想要什么:

- set_fact: 
**node_dict:
node1:
labels:
f-one: n-one
node2:
labels: 
f-two: n-two**  

当我运行时:

- name: check loop1
debug:
msg: '{{item[0]}} - {{item[1]}} - {{ item[2]}} '
with_nested:
- '{{ nodes }}'
- '{{ list_one }}'
- '{{ list_two }}'

item变量是可用的。但是这样做:

- set_fact: 
final:
'{{item[0]}}':
labels:
"{{item[1] }}" : "{{item[2]}}"
with_nested:
- '{{ nodes }}'
- '{{ list_one }}'
- '{{ list_two }}'

导致错误。

有人可以解释为什么吗?我如何得到我想要的结果?

(更新)

使用金贾模板

node_dict: |
{% filter from_yaml %}
{% for n,k,v in nodes|zip(list_one)|zip(list_two)|map('flatten') %}
{{ n }}: {label: { {{ k }}: {{ v }} }}
{% endfor %}
{% endfilter %}

给予你想要的

node_dict:
node1:
label:
f-one: n-one
node2:
label:
f-two: n-two

用于测试的完整行动手册示例

- hosts: localhost

vars:
nodes: [node1, node2]
list_one: [f-one, f-two]
list_two: [n-one, n-two]
node_dict: |
{% filter from_yaml %}
{% for n,k,v in nodes|zip(list_one)|zip(list_two)|map('flatten') %}
{{ n }}: {label: { {{ k }}: {{ v }} }}
{% endfor %}
{% endfilter %}
tasks:
- debug:
var: node_dict

(原产地)

下一个选项是创建标签列表

- set_fact:
my_labels: "{{ my_labels|d([]) +
[{list_one[my_idx]:list_two[my_idx]}] }}"
loop: "{{ nodes }}"
loop_control:
index_var: my_idx

my_labels:
- f-one: n-one
- f-two: n-two

然后合并字典

- set_fact:
node_dict: "{{ node_dict|d({})|
combine({item:{'labels':my_labels[my_idx]}}) }}"
loop: "{{ nodes }}"
loop_control:
index_var: my_idx

给出相同的结果

node_dict:
node1:
labels:
f-one: n-one
node2:
labels:
f-two: n-two

用于测试的完整行动手册示例

- hosts: localhost

vars:
nodes: [node1, node2]
list_one: [f-one, f-two]
list_two: [n-one, n-two]
tasks:
- set_fact:
my_labels: "{{ my_labels|d([]) +
[{list_one[my_idx]:list_two[my_idx]}] }}"
loop: "{{ nodes }}"
loop_control:
index_var: my_idx
- set_fact:
node_dict: "{{ node_dict|d({})|
combine({item:{'labels':my_labels[my_idx]}}) }}"
loop: "{{ nodes }}"
loop_control:
index_var: my_idx
- debug:
var: my_labels
- debug:
var: node_dict
  1. 虽然你上面的最后一段代码不符合你的要求,但它是完全有效的:我在运行它时没有收到任何错误。
  2. 由于您现在正在使用它,set_fact在每个循环中覆盖您的final变量。要像您尝试的那样将元素附加到字典中,您需要将 var 初始化为空字典,并将其与您为每次迭代计算的值组合在一起。由于计算值本身就是字典,因此如果必须在字典深处编写表达式,则需要使用recursive=True
  3. 如果我考虑您的原始数据和预期结果,您希望将每个列表的第N 个元素关联在一起。这不是nested所做的(在nodes上循环list_one子循环在list_two上......在您的情况下,您只需遍历列表长度的索引,并将同一索引的元素组合在一起。我在下面的看法。
---
- name: test for SO
hosts: localhost
vars:
nodes:
- node1
- node2
list_one:
- f-one
- f-two
list_two:
- n-one
- n-two
tasks:
- name: Make my config
set_fact:
final: >-
{{
final
| default({})
| combine ({
nodes[item]: {
'labels': {
list_one[item]: list_two[item]
}
}
}, recursive=True)
}}
loop: "{{ range(nodes | length) | list }}"
- name: debug
debug:
var: final

给出以下结果

$ ansible-playbook test.yml 
PLAY [test for SO] ******************************************************************
TASK [Gathering Facts] **************************************************************
ok: [localhost]
TASK [Make my config] ***************************************************************
ok: [localhost] => (item=0)
ok: [localhost] => (item=1)
TASK [debug] ************************************************************************
ok: [localhost] => {
"final": {
"node1": {
"labels": {
"f-one": "n-one"
}
},
"node2": {
"labels": {
"f-two": "n-two"
}
}
}
}
PLAY RECAP **************************************************************************
localhost                  : ok=3    changed=0    unreachable=0    failed=0 

编辑:使用zip过滤器可以实现相同的结果(我今天(重新)发现阅读其他贡献)。

- name: Make my config
set_fact:
final: >-
{{
final
| default({})
| combine ({
item.0: {
'labels': {
item.1: item.2
}
}
}, recursive=True)
}}
loop: "{{ nodes | zip(list_one, list_two) | list }}"

最新更新