Reputation: 4293
I have a list of items, which all appear as keys in a certain dictionary. I would like to use Jinja2 filters to lookup each list item in the dictionary and return the corresponding value, in a list.
In python this would be:
[my_dict[x] for x in my_list]
What is the Jinja equivalent?
my_list | map(my_dict)
does not work.
Here's a sample playbook.
---
- hosts: localhost
connection: local
vars:
my_dict:
a: 1
b: 2
c: 3
my_list:
- a
- c
tasks:
- assert:
that:
- "{{ actual == expected }}"
vars:
# [my_dict[x] for x in my_list]
actual: "{{ my_list | map(my_dict) | list }}"
expected:
- 1
- 3
If you run this, you get:
fatal: [localhost]: FAILED! => {"msg": "An unhandled exception occurred while templating '{{ my_list | map(my_dict) | list }}'. Error was a <class 'ValueError'>, original message: key must be a string"}
I want to modify the actual:
line so that this playbook runs without error.
Note that I do not want to loop in Ansible itself. This is a simple MWE. In my real example, this lookup should be inline inside a much larger template file.
Upvotes: 2
Views: 2345
Reputation: 67994
Given the list
my_list: [a, c]
Use filter extract
actual: "{{ my_list|map('extract', my_dict)|list }}"
should give
actual: [1, 3]
The above solution doesn't work when some items in the list are missing in the dictionary. For example,
my_list: [a, c, x]
will fail
''dict object'' has no attribute ''x'''
In this case, select the keys that are in the list. The expression below gives the same result
actual: "{{ my_dict|dict2items|
selectattr('key', 'in', my_list)|
map(attribute='value')|list }}"
Example of a complete playbook for testing
- hosts: localhost
vars:
my_list: [a, c]
my_dict:
a: 1
b: 2
c: 3
actual1: "{{ my_list|map('extract', my_dict)|list }}"
actual2: "{{ my_dict|dict2items|
selectattr('key', 'in', my_list)|
map(attribute='value')|list }}"
tasks:
- debug:
var: actual1|to_yaml
- debug:
var: actual2|to_yaml
Upvotes: 4