pythonansible

Ansible: Transforming list to dictionary with items2dict


Given the following list:

fruits:
  - fruit: apple
    color: red
    texture: crunchy
    shape: round
  - fruit: grapefruit
    color: yellow
    taste: sour
  - fruit: pear
    color: yellow

How would I use the items2dict filter to change to a dictionary (below)? Problem is there is multiple, and a variable amount of values.

"{{ fruits | items2dict(key_name='fruit', value_name='??????') }}

Desired result:

fruits:
  - apple:
      color: red
      texture: crunchy
      shape: round
  - grapefruit:
      color: yellow
      taste: sour
  - pear:
      color: yellow

I can't seem to find how here: https://docs.ansible.com/ansible/latest/user_guide/playbooks_filters.html#transforming-lists-into-dictionaries


Solution

  • The task below does the job

        - set_fact:
            fruits2: "{{ fruits2|default([]) + [{ item['fruit']: value }]}}"
          loop: "{{ fruits }}"
          vars:
            keys: "{{ item.keys()|difference(['fruit']) }}"
            vals: "{{ keys|map('extract', item)|list }}"
            value: "{{ dict(keys|zip(vals)) }}"
    

    gives

      fruits2:
      - apple:
          color: red
          shape: round
          texture: crunchy
      - grapefruit:
          color: yellow
          taste: sour
      - pear:
          color: yellow
    

    A dictionary, instead of a list, can be created by simply changing the concatenation of the lists to the combination of the dictionaries e.g.

        - set_fact:
            fruits3: "{{ fruits3|default({})|combine({ item['fruit']: value }) }}"
          loop: "{{ fruits }}"
          vars:
            keys: "{{ item.keys()|difference(['fruit']) }}"
            vals: "{{ keys|map('extract', item)|list }}"
            value: "{{ dict(keys|zip(vals)) }}"
    

    gives

      fruits3:
        apple:
          color: red
          shape: round
          texture: crunchy
        grapefruit:
          color: yellow
          taste: sour
        pear:
          color: yellow
    

    items2dict can be used to select 2 attributes only (key_name and value_name) e.g.

        - set_fact:
            fruits4: "{{ fruits|items2dict(key_name='fruit', value_name='color') }}"
    

    gives

      fruits4:
        apple: red
        grapefruit: yellow
        pear: yellow
    

    A list (desired result) can't be created by items2dict. items2dict returns a dictionary.


    items2dict will fail if the attribute is missing e.g.

        - set_fact:
            fruits5: "{{ fruits|items2dict(key_name='fruit', value_name='taste') }}"
    

    fails

    The error was: KeyError: 'taste'