How to convert a dictionary to a list of dictionaries

916 views
Skip to first unread message

jean-christophe manciot

unread,
Jun 14, 2022, 7:25:07 AM6/14/22
to Ansible Project
I'm faced with a corner case where some devices are expected to return a list of dictionaries but instead return a single dictionary. This creates an error later on in ansible when a list is expected.
For instance, the device returns the file:
        var:
                key_1: value_11
                key_2: value_21
                key_3: value_31

instead of for instance:
        var:
                - key_1: value_11
                  key_2: value_21
                  key_3: value_31
                - key_1: value_12
                  key_2: value_22
                  key_3: value_32
                  ...

So the goal is to transform the first var into:
        var:
                - key_1: value_11
                  key_2: value_21
                  key_3: value_31

AFAIK, there is no ansible filters to accomplish that; for instance, 'list' does not give the expected result. 
Also, we cannot count on the name or number of keys as they may change.
I suppose the solution may revolve around something like that:
        - set_fact:
                list_var: >-
                        {% for key, value in var.items() %}
                                {{ [{key: value}] }}
                        {% endfor %}
          when: >
                (var | type_debug != 'list')

This does not give the expected result either.

Any suggestion?

Vladimir Botka

unread,
Jun 14, 2022, 9:35:46 AM6/14/22
to jean-christophe manciot, ansible...@googlegroups.com
On Tue, 14 Jun 2022 04:25:06 -0700 (PDT)
jean-christophe manciot <actionm...@gmail.com> wrote:

> var:
> key_1: value_11
> key_2: value_21
> key_3: value_31
>
> So the goal is to transform the first var into:
> var:
> - key_1: value_11
> key_2: value_21
> key_3: value_31

Simply close it in the brackets. For example,

- debug:
msg: "{{ [var] }}"

gives

msg:
- key_1: value_11
key_2: value_21
key_3: value_31

, or

var2: "{{ [var] + [var] }}"

gives

var2:
- key_1: value_11
key_2: value_21
key_3: value_31
- key_1: value_11
key_2: value_21
key_3: value_31

--
Vladimir Botka

jean-christophe manciot

unread,
Jun 14, 2022, 9:49:20 AM6/14/22
to Ansible Project
So simple! 
Nice! :-)

Dick Visser

unread,
Jun 14, 2022, 10:19:08 AM6/14/22
to ansible...@googlegroups.com, jean-christophe manciot
On Tue, 14 Jun 2022 at 15:35, Vladimir Botka <vbo...@gmail.com> wrote:
>
> On Tue, 14 Jun 2022 04:25:06 -0700 (PDT)
> jean-christophe manciot <actionm...@gmail.com> wrote:
>
> > var:
> > key_1: value_11
> > key_2: value_21
> > key_3: value_31
> >
> > So the goal is to transform the first var into:
> > var:
> > - key_1: value_11
> > key_2: value_21
> > key_3: value_31
>
> Simply close it in the brackets. For example,
>
> - debug:
> msg: "{{ [var] }}"
>
> gives
>
> msg:
> - key_1: value_11
> key_2: value_21
> key_3: value_31

This works, but if the original var is already a list, you get a list
of a list, which is probably not what the OP wants.
In cases like this I tend to use the "to_array" function of jmespath:

https://jmespath.org/specification.html#to-array

This will always return a list. Example:


---
- hosts: localhost
connection: local
gather_facts: no

vars:
a:
key_1: value_11
key_2: value_21
key_3: value_31
b:
- key_1: value_11
key_2: value_21
key_3: value_31

tasks:
- debug:
msg: "{{ a | json_query('to_array(@)') }}"

- debug:
msg: "{{ b | json_query('to_array(@)') }}"



[WARNING]: No inventory was parsed, only implicit localhost is available

PLAY [localhost]
****************************************************************

TASK [debug] ********************************************************************
ok: [localhost] =>
msg:
- key_1: value_11
key_2: value_21
key_3: value_31

TASK [debug] ********************************************************************
ok: [localhost] =>

Brian Coca

unread,
Jun 14, 2022, 10:40:48 AM6/14/22
to Ansible Project, jean-christophe manciot
many ways to do it conditionally without need for
serializing/deserializing into jaon

var is dict|ternary([var], var)


--
----------
Brian Coca

Dick Visser

unread,
Jun 14, 2022, 3:40:26 PM6/14/22
to ansible...@googlegroups.com, jean-christophe manciot
On Tue, 14 Jun 2022 at 16:40, Brian Coca <bc...@redhat.com> wrote:
>
> many ways to do it conditionally without need for
> serializing/deserializing into jaon
>
> var is dict|ternary([var], var)

With this I get:

No test named ''dict''

Shouldn't it be 'mapping' ?




>
>
> --
> ----------
> Brian Coca
>
> --
> You received this message because you are subscribed to the Google Groups "Ansible Project" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to ansible-proje...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/ansible-project/CACVha7eR5UaKYomO%3DQ%3DTKDgDf6mmro0gJcvkDv0SSe%2Brz3dxsA%40mail.gmail.com.

Brian Coca

unread,
Jun 15, 2022, 10:32:48 AM6/15/22
to Ansible Project
yes, 'mapping' is correct ... this what happens when you respond away
from the computer and don't verify ....

--
----------
Brian Coca

Reply all
Reply to author
Forward
0 new messages