如何在 Ansible 中交替显示多个列表的元素?

How can I alternate the elements of multiple lists in Ansible?

我有多个列表作为输入(所有列表的长度都相同,但输入可以有 3 个以上的列表)。我想创建一个列表,它是所有输入列表交替其元素的总和。

例如,给定以下输入:

data:
  - ['1','2','3','4','5']
  - ['6','7','8','9','10']
  - ['11','12','13','14','15']

我期待以下输出:

lst: [['1','6','11'],['2','7','12'],['3','8','13'],['4','9','14'],['5','10','15']]

这是我试过的:


---
- name: zip more than 3 lists with loop
  hosts: localhost
  tasks:
    - name: Set facts
      set_fact:
        list:
          - ['1','2','3','4','5']
          - ['6','7','8','9','10']
          - ['11','12','13','14','15']

    - name: zip to make pairs of both lists
      set_fact:
        lst: "{{ list[0] | zip(list[1]) | zip(list[2]) | list }}"

    - name: Debug ['1','6','11'],['2','7','13'],...
      debug:
        msg: "{{ item | flatten }}"
      loop: "{{ lst }}"

    - name: zip to make pairs of both lists
      set_fact:
        lst2: "{{ lst2 | default([]) | zip(ansible_loop.nextitem) | list }}"
      loop: "{{ list }}"
      loop_control:
        extended: yes

    - name: Debug
      debug:
        msg: "{{ lst2 }}"

第一个 set_fact 输出循环元素,但 lst 不包括我期望的实际输出。第一个 set_fact 的限制是由于 zip 过滤器,我无法在循环中迭代。我不知道如何实现我的目标。

给定数据

  data:
    - ['1','2','3','4','5']
    - ['6','7','8','9','10']
    - ['11','12','13','14','15']

问:Transpose矩阵。

答:例如

    - set_fact:
        lst: "{{ lst|d(data.0)|zip(item)|map('flatten') }}"
      loop: "{{ data[1:] }}"

给予

  lst:
    - ['1', '6', '11']
    - ['2', '7', '12']
    - ['3', '8', '13']
    - ['4', '9', '14']
    - ['5', '10', '15']

系统的方法是为 Python NumPy package. For example, starting with numpy.matrix.transpose

创建包装器
shell> cat filter_plugins/numpy.py
import json
import numpy


def numpy_transpose(arr):
    arr1 = numpy.array(arr)
    arr2 = arr1.transpose()
    return json.dumps(arr2.tolist())


class FilterModule(object):
    ''' Ansible wrappers for Python NumPy methods '''

    def filters(self):
        return {
            'numpy_transpose': numpy_transpose,
        }

下面的声明在没有迭代的情况下给出了相同的结果

  lst: "{{ data|numpy_transpose()|from_yaml }}"

初步说明:list是jinja2过滤器的名称,我非常强烈建议您不要将其用作变量名


Ansible 主要是 python 兼容,您可以利用 * 解包运算符将您的列表元素转换为您正在调用的 function/filter 的参数,它正在接受一个变量参数数量(如下面的 ziplookup)。

以下剧本适用于 data_list 中任意数量的列表(只要这个数字严格优于 1...)

---
- name: zip more than 3 lists with loop
  hosts: localhost

  vars:
    data_list:
      - ['1','2','3','4','5']
      - ['6','7','8','9','10']
      - ['11','12','13','14','15']

    # You can do this with your original zip tentative
    alternated_list1: "{{ (data_list | first) | zip(*data_list[1:]) }}"

    # But I find it more elegant with the together lookup here
    alternated_list2: "{{ lookup('together', *data_list) }}"

  tasks:
    - name: calculated with zip
      debug:
        var: alternated_list1

    - name: calculated with together lookup
      debug:
        var: alternated_list2

    - name: And of course you can use the result, for example in a loop
      debug:
        var: item
      loop: "{{ alternated_list2 }}"

并给出:

PLAY [zip more than 3 lists with loop] ********************************************************************************************************************************

TASK [Gathering Facts] ************************************************************************************************************************************************
ok: [localhost]

TASK [calculated with zip] ********************************************************************************************************************************************
ok: [localhost] => {
    "alternated_list1": [
        [
            "1",
            "6",
            "11"
        ],
        [
            "2",
            "7",
            "12"
        ],
        [
            "3",
            "8",
            "13"
        ],
        [
            "4",
            "9",
            "14"
        ],
        [
            "5",
            "10",
            "15"
        ]
    ]
}

TASK [calculated with together lookup] ********************************************************************************************************************************
ok: [localhost] => {
    "alternated_list2": [
        [
            "1",
            "6",
            "11"
        ],
        [
            "2",
            "7",
            "12"
        ],
        [
            "3",
            "8",
            "13"
        ],
        [
            "4",
            "9",
            "14"
        ],
        [
            "5",
            "10",
            "15"
        ]
    ]
}

TASK [And of course you can use the result, for example in a loop] ****************************************************************************************************
ok: [localhost] => (item=['1', '6', '11']) => {
    "ansible_loop_var": "item",
    "item": [
        "1",
        "6",
        "11"
    ]
}
ok: [localhost] => (item=['2', '7', '12']) => {
    "ansible_loop_var": "item",
    "item": [
        "2",
        "7",
        "12"
    ]
}
ok: [localhost] => (item=['3', '8', '13']) => {
    "ansible_loop_var": "item",
    "item": [
        "3",
        "8",
        "13"
    ]
}
ok: [localhost] => (item=['4', '9', '14']) => {
    "ansible_loop_var": "item",
    "item": [
        "4",
        "9",
        "14"
    ]
}
ok: [localhost] => (item=['5', '10', '15']) => {
    "ansible_loop_var": "item",
    "item": [
        "5",
        "10",
        "15"
    ]
}

PLAY RECAP ************************************************************************************************************************************************************
localhost                  : ok=4    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0