我需要将一个具有列表值的字典转换为一个字典列表。
给定:
my_dict:
key1: ["111", "222"]
key2: ["444", "555"]
所需输出:
my_list:
- key1: "111"
key2: "444"
- key1: "222"
key2: "555"
我试过了:
- set_fact:
my_list: "{{ my_list | default([]) + [{item.0.key: item.1}] }}"
loop: "{{ my_dict | dict2items | subelements('value') }}"
我得到了什么:
[
{
"key1": "111"
},
{
"key1": "222"
},
{
"key2": "444"
},
{
"key2": "555"
}
]
感谢任何帮助和建议!
首先获取字典的键和值
keys: "{{ my_dict.keys()|list }}"
vals: "{{ my_dict.values()|list }}"
为
keys: [key1, key2]
vals:
- ['111', '222']
- ['444', '555']
转置
- set_fact:
tvals: "{{ tvals|d(vals.0)|zip(item)|map('flatten') }}"
loop: "{{ vals[1:] }}"
为
tvals:
- ['111', '444']
- ['222', '555']
创建字典列表
my_list: "{{ tvals|map('zip', keys)|
map('map', 'reverse')|
map('community.general.dict')|
list }}"
为
my_list:
- key1: '111'
key2: '444'
- key1: '222'
key2: '555'
指出<一口>
- 完整剧本示例
- hosts: localhost
vars:
my_dict:
key1: ["111", "222"]
key2: ["444", "555"]
keys: "{{ my_dict.keys()|list }}"
vals: "{{ my_dict.values()|list }}"
my_list: "{{ tvals|map('zip', keys)|
map('map', 'reverse')|
map('community.general.dict')|
list }}"
tasks:
- set_fact:
tvals: "{{ tvals|d(vals.0)|zip(item)|map('flatten') }}"
loop: "{{ vals[1:] }}"
- debug:
var: my_list
- 您可以使用自定义过滤器来转置矩阵。例如,
shell> cat filter_plugins/numpy.py
# All rights reserved (c) 2022, Vladimir Botka <vbotka@gmail.com>
# Simplified BSD License, https://opensource.org/licenses/BSD-2-Clause
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
from ansible.errors import AnsibleFilterError
from ansible.module_utils.common._collections_compat import Sequence
import json
import numpy
def numpy_transpose(arr):
if not isinstance(arr, Sequence):
raise AnsibleFilterError('First argument for numpy_transpose must be list. %s is %s' %
(arr, type(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,
}
则可以避免迭代。例如,下面的剧本给出了相同的结果
- hosts: localhost
vars:
my_dict:
key1: ["111", "222"]
key2: ["444", "555"]
keys: "{{ my_dict.keys()|list }}"
vals: "{{ my_dict.values()|list }}"
tvals: "{{ vals|numpy_transpose()|from_yaml }}"
my_list: "{{ tvals|map('zip', keys)|
map('map', 'reverse')|
map('community.general.dict')|
list }}"
tasks:
- debug:
var: my_list
- 转位解释
让我们从矩阵2x2
开始vals:
- ['111', '222']
- ['444', '555']
下面的任务
- set_fact:
tvals: "{{ tvals|d(vals.0)|zip(item) }}"
loop: "{{ vals[1:] }}"
给出step by step:
a)在迭代开始之前,变量tvals被赋值为默认值vals。0
vals.0: ['111', '222']
b)任务迭代列表vals[1:]。这些是数组中的所有行,除了第一行
vals[1:]:
- ['444', '555']
c)第一次,也是唯一一次,迭代压缩第一行和第二行。这是结果
vals.0|zip(vals.1):
- ['111', '444']
- ['222', '555']
我们继续看矩阵3x3
vals:
- ['111', '222', '333']
- ['444', '555', '666']
- ['777', '888', '999']
下面的任务
- set_fact:
tvals: "{{ tvals|d(vals.0)|zip(item)|map('flatten') }}"
loop: "{{ vals[1:] }}"
给出step by step:
a)在迭代开始之前,变量tvals被赋值为默认值vals。0
vals.0: ['111', '222', '333']
b)任务迭代列表vals[1:]
vals[1:]:
- ['444', '555', '666']
- ['777', '888', '999']
c)第一次迭代压缩第一行和第二行,并将其分配给tvals。过滤器flatten对
行没有影响。vals.0|zip(vals.1)|map('flatten'):
- ['111', '444']
- ['222', '555']
- ['333', '666']
d)下一个迭代zip值和第三行
tvals|zip(vals.2):
- - ['111', '444']
- '777'
- - ['222', '555']
- '888'
- - ['333', '666']
- '999
e)这些线必须变平。这是结果
tvals|zip(vals.2)|map('flatten'):
- ['111', '444', '777']
- ['222', '555', '888']
- ['333', '666', '999']
一口>