AnsiblePilot — Master Ansible Automation

AnsiblePilot is the leading resource for learning Ansible automation, DevOps, and infrastructure as code. Browse over 1,400 tutorials covering Ansible modules, playbooks, roles, collections, and real-world examples. Whether you are a beginner or an experienced engineer, our step-by-step guides help you automate Linux, Windows, cloud, containers, and network infrastructure.

Popular Topics

About Luca Berton

Luca Berton is an Ansible automation expert, author of 8 Ansible books published by Apress and Leanpub including "Ansible for VMware by Examples" and "Ansible for Kubernetes by Example", and creator of the Ansible Pilot YouTube channel. He shares practical automation knowledge through tutorials, books, and video courses to help IT professionals and DevOps engineers master infrastructure automation.

Ansible Convert Dict to List: dict2items & items2dict (Guide)

By Luca Berton · Published 2024-01-01 · Category: troubleshooting

How to convert dictionaries to lists in Ansible with dict2items and items2dict filters. Transform data structures for loops, filtering, and manipulation.

Introduction

When working with Ansible, automating data manipulation is crucial for dynamic and scalable playbooks. A common scenario involves converting a list of dictionaries into a simple list for further processing. In this guide, we’ll explore how to achieve this transformation effectively using Jinja2 filters in Ansible.

See also: Ansible Split String: Filter Guide for CSV, Delimiters & Lists

Problem Statement

You may encounter a data structure like this:

data_structure:
  - name: a
  - name: b
  - name: c

Your goal is to extract the values of the name key into a simple list:

['a', 'b', 'c']

Let’s explore the solution step by step.

Ansible Solution with Jinja2 Filters

Ansible’s Jinja2 templating engine provides powerful filters like map and list to simplify this task.

Example Playbook

Here’s a playbook to convert the given data structure into a list:
- name: Convert dictionaries to a list in Ansible
  hosts: localhost
  gather_facts: no
  vars:
    data_structure:
      - name: a
      - name: b
      - name: c
  tasks:
    - name: Extract values into a list
      set_fact:
        extracted_list: "{{ data_structure | map(attribute='name') | list }}"

- name: Debug the extracted list debug: var: extracted_list

- name: Use the extracted list in a loop debug: msg: "Processing item: {{ item }}" loop: "{{ extracted_list }}"

Explanation of Filters

map(attribute='name'): Extracts the value of the name key from each dictionary in the list. | list: Converts the resulting generator into a proper list.

Debugging Output

The debug task will display the extracted list:
ok: [localhost] => {
    "extracted_list": [
        "a",
        "b",
        "c"
    ]
}

See also: Ansible from_json & to_json Filters: Parse & Generate JSON Data (Guide)

Handling Common Errors

Error: "Invalid data passed to loop"

If Ansible complains about invalid data, the issue may lie in how the data is interpreted. Use these additional filters to ensure the data is processed correctly:
- name: Ensure extracted list is properly formatted
  set_fact:
    parsed_list: "{{ extracted_list | to_json | from_json }}"

This serialization-deserialization process guarantees the data is treated as a list.

Conclusion

Transforming data structures in Ansible is straightforward with the right filters. By leveraging Jinja2’s map and list filters, you can easily convert dictionaries into lists for dynamic playbook operations. Debugging tools and careful handling of data ensure smooth execution and accurate results.

See also: Ansible Transform JSON Data: Filters for Parsing & Manipulating JSON

Dictionary to List Conversion

dict2items filter

- name: Convert dict to list of key/value pairs
  vars:
    users:
      alice: admin
      bob: developer
      charlie: viewer
  debug:
    msg: "{{ users | dict2items }}"
  # Output:
  # [{"key": "alice", "value": "admin"},
  #  {"key": "bob", "value": "developer"},
  #  {"key": "charlie", "value": "viewer"}]

Loop over dictionary using dict2items

- name: Create users from dictionary
  vars:
    user_roles:
      alice: admin
      bob: developer
      charlie: viewer
  ansible.builtin.user:
    name: "{{ item.key }}"
    comment: "{{ item.value }}"
  loop: "{{ user_roles | dict2items }}"
  become: true

Custom key/value names

- debug:
    msg: "{{ users | dict2items(key_name='username', value_name='role') }}"
  # Output:
  # [{"username": "alice", "role": "admin"}, ...]

List to Dictionary Conversion

items2dict filter

- name: Convert list back to dictionary
  vars:
    user_list:
      - key: alice
        value: admin
      - key: bob
        value: developer
  debug:
    msg: "{{ user_list | items2dict }}"
  # Output: {"alice": "admin", "bob": "developer"}

With custom key/value names

- vars:
    servers:
      - name: web1
        ip: 192.168.1.10
      - name: web2
        ip: 192.168.1.11
  debug:
    msg: "{{ servers | items2dict(key_name='name', value_name='ip') }}"
  # Output: {"web1": "192.168.1.10", "web2": "192.168.1.11"}

Advanced Transformations

Filter dictionary entries

- name: Get only admin users
  vars:
    users:
      alice: admin
      bob: developer
      charlie: admin
  debug:
    msg: "{{ users | dict2items | selectattr('value', 'eq', 'admin') | items2dict }}"
  # Output: {"alice": "admin", "charlie": "admin"}

Merge two dictionaries

- name: Merge defaults with overrides
  vars:
    defaults:
      port: 8080
      debug: false
      log_level: info
    overrides:
      debug: true
      port: 9090
  debug:
    msg: "{{ defaults | combine(overrides) }}"
  # Output: {"port": 9090, "debug": true, "log_level": "info"}

Group list items into dictionary

- name: Group servers by role
  vars:
    servers:
      - name: web1
        role: web
      - name: web2
        role: web
      - name: db1
        role: database
  debug:
    msg: "{{ servers | groupby('role') | items2dict(key_name=0, value_name=1) }}"

Quick Reference

| Filter | Direction | Input → Output | |--------|-----------|----------------| | dict2items | Dict → List | {a: 1}[{key: a, value: 1}] | | items2dict | List → Dict | [{key: a, value: 1}]{a: 1} | | combine | Dict + Dict | Merge two dicts | | groupby | List → Grouped | Group by attribute | | map(attribute=) | List → Values | Extract one field |

FAQ

When should I use dict2items vs looping directly?

Use dict2items when you need both key and value in the loop. If you only need keys, use dict.keys(). If only values, use dict.values().

How do I convert a flat list to a dict?

Use zip with two lists:

- vars:
    keys: [name, age, city]
    values: [Alice, 30, London]
  debug:
    msg: "{{ dict(keys | zip(values)) }}"
  # Output: {"name": "Alice", "age": 30, "city": "London"}

dict2items — Dict to List

- vars:
    users:
      alice: { uid: 1001, shell: /bin/bash }
      bob: { uid: 1002, shell: /bin/zsh }
      charlie: { uid: 1003, shell: /bin/bash }
  debug:
    msg: "{{ users | dict2items }}"
# [
#   {"key": "alice", "value": {"uid": 1001, "shell": "/bin/bash"}},
#   {"key": "bob", "value": {"uid": 1002, "shell": "/bin/zsh"}},
#   {"key": "charlie", "value": {"uid": 1003, "shell": "/bin/bash"}}
# ]

items2dict — List to Dict

- vars:
    user_list:
      - { key: alice, value: admin }
      - { key: bob, value: developer }
  debug:
    msg: "{{ user_list | items2dict }}"
# {"alice": "admin", "bob": "developer"}

Custom Key/Value Names

- vars:
    services:
      - { name: nginx, port: 80 }
      - { name: redis, port: 6379 }
      - { name: postgres, port: 5432 }
  debug:
    msg: "{{ services | items2dict(key_name='name', value_name='port') }}"
# {"nginx": 80, "redis": 6379, "postgres": 5432}

Loop Over Dict

# Direct dict loop
- user:
    name: "{{ item.key }}"
    uid: "{{ item.value.uid }}"
    shell: "{{ item.value.shell }}"
  loop: "{{ users | dict2items }}"
  become: true

Filter Dict Items

# Only bash users
- set_fact:
    bash_users: "{{ users | dict2items | selectattr('value.shell', 'eq', '/bin/bash') | list }}"

# Convert back to dict - set_fact: bash_users_dict: "{{ bash_users | items2dict }}"

Sort Dict by Value

- vars:
    scores: { alice: 95, bob: 87, charlie: 92 }
  debug:
    msg: "{{ scores | dict2items | sort(attribute='value', reverse=true) }}"
# Sorted: alice(95), charlie(92), bob(87)

Transform and Rebuild

# Add prefix to all keys
- vars:
    config:
      host: localhost
      port: 5432
      name: mydb
  set_fact:
    prefixed: "{{ config | dict2items | map('combine', {'key': 'DB_' + item.key | upper}) | items2dict }}"

Practical: Environment Variables

- vars:
    env_vars:
      DB_HOST: db.internal
      DB_PORT: "5432"
      REDIS_URL: "redis://cache:6379"
      APP_ENV: production
  copy:
    content: |
      {% for item in env_vars | dict2items | sort(attribute='key') %}
      {{ item.key }}={{ item.value }}
      {% endfor %}
    dest: /etc/myapp/.env

Practical: Package Management

- vars:
    packages:
      nginx: present
      redis: present
      old-app: absent
  apt:
    name: "{{ item.key }}"
    state: "{{ item.value }}"
  loop: "{{ packages | dict2items }}"
  become: true

Merge and Transform

# Combine two dicts and iterate
- vars:
    defaults: { log_level: info, workers: 4 }
    overrides: { log_level: debug }
  set_fact:
    merged: "{{ defaults | combine(overrides) }}"

- debug: msg: "{{ item.key }}={{ item.value }}" loop: "{{ merged | dict2items }}"

| Filter | Input → Output | |--------|---------------| | dict2items | Dict → List of {key, value} | | items2dict | List of {key, value} → Dict | | combine | Two dicts → Merged dict | | map(attribute=) | List → Extract field | | selectattr | List → Filter by attribute | | groupby | List → Group by field |

FAQ

When do I need dict2items?

When you need to loop over a dictionary, filter it with selectattr, or sort it. Ansible loops work with lists, not dicts.

Can I use with_dict instead?

with_dict is the old way. Modern Ansible uses loop: "{{ mydict | dict2items }}". Both work, but dict2items is more flexible.

How do I get just the keys or values?

keys: "{{ mydict.keys() | list }}"
values: "{{ mydict.values() | list }}"

Related Articles

Jinja2 filters in Ansible templatesAnsible JSON Conversion Guidecapturing output with Ansible commandAnsible loop patterns and tips

Category: troubleshooting

Browse all Ansible tutorials · AnsiblePilot Home