Цикл по произведению двух списков словарей (Ansible/Jinja2)

Вопрос или проблема

У меня есть два списка словарей, и я хотел бы пройтись по декартовому произведению как по одному. Как мне это сделать.

образцы данных:

environments: [
                {title: outdoors, climate: variable},
                {title: indoors, climate: steady}
              ],
colorscheme:  [
                {top: blue, bottom: red},
                {top: pink, bottom: green}
              ]

желаемый результат:

item: [
        {title: outdoors, climate: variable, top: blue, bottom: red},
        {title: indoors, climate: steady, top: blue, bottom: red},
        {title: outdoors, climate: variable, top: pink, bottom: green},
        {title: indoors, climate: steady, top: pink, bottom: green}
      ]

Я пробовал выражение "{{ environments|product(colorscheme)|list }}", которое приближает меня к желаемому, но не совсем то, что я хочу.

Результаты выражения:

item: [
        [
          {title: outdoors, climate: variable}, 
          {top: blue, bottom: red}
        ],
        [
          {title: indoors, climate: steady},
          {top: blue, bottom: red}
        ],
        [
           {title: outdoors, climate: variable},
           {top: pink, bottom: green}
        ],
        [
           {title: indoors, climate: steady},
           {top: pink, bottom: green}
        ]
      ]

Вот один из способов, как это можно сделать. Не уверен, что это лучший способ.

- hosts: localhost
  gather_facts: no
  vars:
    envs:
    - title: outdoors
      climate: variable
    - title: indoors
      climate: steady
    colorscheme:
    - top: blue
      bottom: red
    - top: pink
      bottom: green
  tasks:
  - debug:
      msg: >
        [
        {% for e in envs %}
        {% for c in colorscheme %}
        {{ e | combine (c) }},
        {% endfor %}
        {% endfor %}
        ]

# TASK [debug] **************************************************************************************************[3/1813$
# ok: [localhost] => {
#     "msg": [
#         {
#             "bottom": "red",
#             "climate": "variable",
#             "title": "outdoors",
#             "top": "blue"
#         },
#         {
#             "bottom": "green",
#             "climate": "variable",
#             "title": "outdoors",
#             "top": "pink"
#         },
#         {
#             "bottom": "red",
#             "climate": "steady",
#             "title": "indoors",
#             "top": "blue"
#         },
#         {
#             "bottom": "green",
#             "climate": "steady",
#             "title": "indoors",
#             "top": "pink"
#         }
#     ]
# }
#

Следующий (крайне уродливый) шаблон Jinja отобразит точно то, что просит автор:

item: [{% for c in colorscheme %}{% for e in environments %}
         {% set noop = e.update(c) -%}{{ e }}{% if not loop.last %},{% endif %}{% endfor %}{% if not loop.last %},{% endif %}{% endfor %}
       ]

или, для удобочитаемости, вот тот же шаблон с добавленным пробелом:

item: [
    {% for c in colorscheme %}
        {% for e in environments %}
            {% set noop = e.update(c) -%}
            {{ e }}
            {% if not loop.last %},{% endif %}
        {% endfor %}
        {% if not loop.last %},{% endif %}
    {% endfor %}
]

Ответ или решение

Для выполнения задачи по созданию декартова произведения двух списков словарей в Ansible с использованием Jinja2, мы можем воспользоваться вложенными циклами. Цель заключается в объединении каждого элемента из одного списка со всеми элементами из другого списка. Давайте подробно рассмотрим, как этого можно достичь, опираясь на предоставленные данные.

Исходные данные

Рассмотрим два списка словарей: environments и colorscheme.

environments: [
    {title: outdoors, climate: variable},
    {title: indoors, climate: steady}
],
colorscheme:  [
    {top: blue, bottom: red},
    {top: pink, bottom: green}
]

Ожидаемый результат

Вы хотите получить следующий результат:

item: [
    {title: outdoors, climate: variable, top: blue, bottom: red},
    {title: indoors, climate: steady, top: blue, bottom: red},
    {title: outdoors, climate: variable, top: pink, bottom: green},
    {title: indoors, climate: steady, top: pink, bottom: green}
]

Реализация в Ansible с использованием Jinja2

Для реализации этой задачи, мы воспользуемся двумя вложенными циклами в шаблоне Jinja2. Ниже представлен код, который выполняет поставленную задачу:

- hosts: localhost
  gather_facts: no
  vars:
    environments:
      - title: outdoors
        climate: variable
      - title: indoors
        climate: steady
    colorscheme:
      - top: blue
        bottom: red
      - top: pink
        bottom: green
  tasks:
    - name: Generate Cartesian product
      debug:
        msg: |
          item: [
          {% for c in colorscheme %}
              {% for e in environments %}
                  {% set combined = e | combine(c) %}
                  {{ combined }}{% if not loop.last %},{% endif %}
              {% endfor %}
              {% if not loop.last %},{% endif %}
          {% endfor %}
          ]

Пояснение кода

  1. Входные данные: Мы определяем два списка переменных environments и colorscheme, содержащих словари с необходимыми свойствами.

  2. Отладка: Задача debug используется для отображения результата. Внутри задачи мы используем блок msg, чтобы создать строку с требуемой структурой.

  3. Вложенные циклы:

    • Внешний цикл (for c in colorscheme) перебирает каждую цветовую схему.
    • Внутренний цикл (for e in environments) перебирает каждую среду.
    • Внутри внутреннего цикла мы используем фильтр combine для объединения текущих словарей из обоих списков в новый словарь combined.
  4. Форматирование вывода: Мы добавляем запятые между элементами, избегая их в конце списка, что делает вывод аккуратным и соответствующим ожидаемому формату.

Заключение

При выполнении этого кода с использованием Ansible вы получите требуемый декартов продукт, что позволит вам эффективно работать со списками словарей для достижения нужного результата. Обратите внимание на необходимость учета различных пустых мест и форматирования, чтобы результат выглядел корректно и в соответствии с ожиданиями.

Оцените материал
Добавить комментарий

Капча загружается...