I want to convert the values of a dictionary into strings and lowercase them, then map over the dict to join each item pair with an =
, and then join the items with a ,
.
Example input:
{"A": "Aardvark", "B": "Beaver", "C": "Cat"}
Desired output:
A=aardvark,B=beaver,C=cat
I actually don't care about the order that A, B, C arrive in, but I want to make sure that I the keys and values don't get mixed up in the end, i.e., no A=cat
or whatever.
What I'm doing now is this:
{{ foo.keys() | zip(foo.values() | map("lower")) | map("join", "=") | join(",") }}
It works so far with the test data I have given it. However, I am not sure that this is guaranteed to be correct, nor do I think this is the most efficient or elegant way to solve this. Is there a better way to map the lower
function over the values in the dict?
I tried using dict2items
and specifying an attribute
on the map
function, but I get an error about an unexpected keyword arg when I do this, plus it's really ugly:
{{ (foo | dict2items | map("lower", attribute="value") | list | items2dict).items() | map("join", "=") | join(",") }}
Note: I am using Ansible 2.9 on Python 3.5 right now, but would really like a solution that works regardless of the Python version.
You could use a custom filter.
Create a filter_plugins/
folder in your playbook folder (I have named the file myfilters.py
and the filter cstring
)
myfilters.py
in folder filter_plugins/
:
#!/usr/bin/python
class FilterModule(object):
def filters(self):
return {
'cstring': self.cstring
}
def cstring(self, data):
result = ""
for k in data:
result += (',' if result else '') + k + '=' + data[k].lower()
return result
playbook:
- name: "tips1"
hosts: localhost
vars:
foo: {"A": "Aardvark", "B": "Beaver", "C": "Cat"}
tasks:
- name: debug users
set_fact:
result: "{{ foo | cstring }}"
- name: display result
debug:
var: result
result:
ok: [localhost] => {
"result": "A=aardvark,B=beaver,C=cat"
}
The advantage of using a custom filter is to do complex things or lot of operations with only one action.