创建子字典键值对的笛卡尔积
Creating cartesian product of sub-dictionary key-val pairs
我有这本字典:
d = {
'hosts': [{'hostname': 'ijk,uvw,xyz', 'ip': '127.0.0.3,127.0.0.4,127.0.0.5', 'extra': 'check-me,check-this,check-it'},{'hostname': 'abc,def', 'ip': '127.0.0.1,127.0.0.2, 'extra': 'check-for,check-this}]}
我想要一个字典,里面有 key-val 对的笛卡尔积。
我需要从中创建以下字典:
d = {
'hosts': [
{'hostname': 'ijk', 'ip': '127.0.0.3', 'extra': 'check-me'},
{'hostname': 'uvw', 'ip': '127.0.0.4', 'extra': 'check-me'},
{'hostname': 'xyz', 'ip': '127.0.0.5', 'extra': 'check-me'},
{'hostname': 'ijk', 'ip': '127.0.0.3', 'extra': 'check-it'},
{'hostname': 'uvw', 'ip': '127.0.0.4', 'extra': 'check-it'},
{'hostname': 'xyz', 'ip': '127.0.0.5', 'extra': 'check-it'},
{'hostname': 'ijk', 'ip': '127.0.0.3', 'extra': 'check-this'},
{'hostname': 'uvw', 'ip': '127.0.0.4', 'extra': 'check-this'},
{'hostname': 'xyz', 'ip': '127.0.0.5', 'extra': 'check-this'},
{'hostname': 'abc', 'ip': '127.0.0.1', 'extra': 'check-for'},
{'hostname': 'abc', 'ip': '127.0.0.1', 'extra': 'check-this'}
{'hostname': 'def', 'ip': '127.0.0.2', 'extra': 'check-for'},
{'hostname': 'def', 'ip': '127.0.0.2', 'extra': 'check-this'}
]
}
提取所有可能的值后,您可以使用 itertools.product
:
组合它们
for host in d['hosts']:
hostnames.extend(host['hostname'].split(','))
ips.extend(host['ip'].split(','))
extras.extend(host['extra'].split(','))
result = {'hosts': []}
for (hostname, ip, extra) in product(hostnames, ips, extras):
result['hosts'].append({'hostname': hostname, 'ip': ip, 'extra': extra})
这会产生笛卡尔积,但这意味着您还可以获得主机名和 IP 之间的所有组合。所以你必须跟踪主机名 -> IP 映射:
result = {'hosts': []}
for host in d['hosts']:
hostnames = host['hostname'].split(',')
ips = host['ip'].split(',')
host2ip = {hostname: ip for hostname, ip in zip(hostnames, ips)}
extras = host['extra'].split(',')
for (hostname, extra) in product(hostnames, extras):
result['hosts'].append({'hostname': hostname, 'ip': host2ip[hostname], 'extra': extra})
这给了
{'hosts': [{'extra': 'check-me', 'hostname': 'ijk', 'ip': '127.0.0.3'},
{'extra': 'check-this', 'hostname': 'ijk', 'ip': '127.0.0.3'},
{'extra': 'check-it', 'hostname': 'ijk', 'ip': '127.0.0.3'},
{'extra': 'check-me', 'hostname': 'uvw', 'ip': '127.0.0.4'},
{'extra': 'check-this', 'hostname': 'uvw', 'ip': '127.0.0.4'},
{'extra': 'check-it', 'hostname': 'uvw', 'ip': '127.0.0.4'},
{'extra': 'check-me', 'hostname': 'xyz', 'ip': '127.0.0.5'},
{'extra': 'check-this', 'hostname': 'xyz', 'ip': '127.0.0.5'},
{'extra': 'check-it', 'hostname': 'xyz', 'ip': '127.0.0.5'},
{'extra': 'check-for', 'hostname': 'abc', 'ip': '127.0.0.1'},
{'extra': 'check-this', 'hostname': 'abc', 'ip': '127.0.0.1'},
{'extra': 'check-for', 'hostname': 'def', 'ip': '127.0.0.2'},
{'extra': 'check-this', 'hostname': 'def', 'ip': '127.0.0.2'}]}
一种方法:
from itertools import product, chain
def f(d):
t = product(zip(*(z := [d[k].split(',') for k in d])[:2]), z[2])
return [dict(zip(d, (*x, y))) for x, y in t]
{'hosts': [*chain(*map(f, d['hosts']))]}
输出:
{'hosts': [{'hostname': 'ijk', 'ip': '127.0.0.3', 'extra': 'check-me'},
{'hostname': 'ijk', 'ip': '127.0.0.3', 'extra': 'check-this'},
{'hostname': 'ijk', 'ip': '127.0.0.3', 'extra': 'check-it'},
{'hostname': 'uvw', 'ip': '127.0.0.4', 'extra': 'check-me'},
{'hostname': 'uvw', 'ip': '127.0.0.4', 'extra': 'check-this'},
{'hostname': 'uvw', 'ip': '127.0.0.4', 'extra': 'check-it'},
{'hostname': 'xyz', 'ip': '127.0.0.5', 'extra': 'check-me'},
{'hostname': 'xyz', 'ip': '127.0.0.5', 'extra': 'check-this'},
{'hostname': 'xyz', 'ip': '127.0.0.5', 'extra': 'check-it'},
{'hostname': 'abc', 'ip': '127.0.0.1', 'extra': 'check-for'},
{'hostname': 'abc', 'ip': '127.0.0.1', 'extra': 'check-this'},
{'hostname': 'def', 'ip': '127.0.0.2', 'extra': 'check-for'},
{'hostname': 'def', 'ip': '127.0.0.2', 'extra': 'check-this'}]}
我有这本字典:
d = {
'hosts': [{'hostname': 'ijk,uvw,xyz', 'ip': '127.0.0.3,127.0.0.4,127.0.0.5', 'extra': 'check-me,check-this,check-it'},{'hostname': 'abc,def', 'ip': '127.0.0.1,127.0.0.2, 'extra': 'check-for,check-this}]}
我想要一个字典,里面有 key-val 对的笛卡尔积。
我需要从中创建以下字典:
d = {
'hosts': [
{'hostname': 'ijk', 'ip': '127.0.0.3', 'extra': 'check-me'},
{'hostname': 'uvw', 'ip': '127.0.0.4', 'extra': 'check-me'},
{'hostname': 'xyz', 'ip': '127.0.0.5', 'extra': 'check-me'},
{'hostname': 'ijk', 'ip': '127.0.0.3', 'extra': 'check-it'},
{'hostname': 'uvw', 'ip': '127.0.0.4', 'extra': 'check-it'},
{'hostname': 'xyz', 'ip': '127.0.0.5', 'extra': 'check-it'},
{'hostname': 'ijk', 'ip': '127.0.0.3', 'extra': 'check-this'},
{'hostname': 'uvw', 'ip': '127.0.0.4', 'extra': 'check-this'},
{'hostname': 'xyz', 'ip': '127.0.0.5', 'extra': 'check-this'},
{'hostname': 'abc', 'ip': '127.0.0.1', 'extra': 'check-for'},
{'hostname': 'abc', 'ip': '127.0.0.1', 'extra': 'check-this'}
{'hostname': 'def', 'ip': '127.0.0.2', 'extra': 'check-for'},
{'hostname': 'def', 'ip': '127.0.0.2', 'extra': 'check-this'}
]
}
提取所有可能的值后,您可以使用 itertools.product
:
for host in d['hosts']:
hostnames.extend(host['hostname'].split(','))
ips.extend(host['ip'].split(','))
extras.extend(host['extra'].split(','))
result = {'hosts': []}
for (hostname, ip, extra) in product(hostnames, ips, extras):
result['hosts'].append({'hostname': hostname, 'ip': ip, 'extra': extra})
这会产生笛卡尔积,但这意味着您还可以获得主机名和 IP 之间的所有组合。所以你必须跟踪主机名 -> IP 映射:
result = {'hosts': []}
for host in d['hosts']:
hostnames = host['hostname'].split(',')
ips = host['ip'].split(',')
host2ip = {hostname: ip for hostname, ip in zip(hostnames, ips)}
extras = host['extra'].split(',')
for (hostname, extra) in product(hostnames, extras):
result['hosts'].append({'hostname': hostname, 'ip': host2ip[hostname], 'extra': extra})
这给了
{'hosts': [{'extra': 'check-me', 'hostname': 'ijk', 'ip': '127.0.0.3'},
{'extra': 'check-this', 'hostname': 'ijk', 'ip': '127.0.0.3'},
{'extra': 'check-it', 'hostname': 'ijk', 'ip': '127.0.0.3'},
{'extra': 'check-me', 'hostname': 'uvw', 'ip': '127.0.0.4'},
{'extra': 'check-this', 'hostname': 'uvw', 'ip': '127.0.0.4'},
{'extra': 'check-it', 'hostname': 'uvw', 'ip': '127.0.0.4'},
{'extra': 'check-me', 'hostname': 'xyz', 'ip': '127.0.0.5'},
{'extra': 'check-this', 'hostname': 'xyz', 'ip': '127.0.0.5'},
{'extra': 'check-it', 'hostname': 'xyz', 'ip': '127.0.0.5'},
{'extra': 'check-for', 'hostname': 'abc', 'ip': '127.0.0.1'},
{'extra': 'check-this', 'hostname': 'abc', 'ip': '127.0.0.1'},
{'extra': 'check-for', 'hostname': 'def', 'ip': '127.0.0.2'},
{'extra': 'check-this', 'hostname': 'def', 'ip': '127.0.0.2'}]}
一种方法:
from itertools import product, chain
def f(d):
t = product(zip(*(z := [d[k].split(',') for k in d])[:2]), z[2])
return [dict(zip(d, (*x, y))) for x, y in t]
{'hosts': [*chain(*map(f, d['hosts']))]}
输出:
{'hosts': [{'hostname': 'ijk', 'ip': '127.0.0.3', 'extra': 'check-me'},
{'hostname': 'ijk', 'ip': '127.0.0.3', 'extra': 'check-this'},
{'hostname': 'ijk', 'ip': '127.0.0.3', 'extra': 'check-it'},
{'hostname': 'uvw', 'ip': '127.0.0.4', 'extra': 'check-me'},
{'hostname': 'uvw', 'ip': '127.0.0.4', 'extra': 'check-this'},
{'hostname': 'uvw', 'ip': '127.0.0.4', 'extra': 'check-it'},
{'hostname': 'xyz', 'ip': '127.0.0.5', 'extra': 'check-me'},
{'hostname': 'xyz', 'ip': '127.0.0.5', 'extra': 'check-this'},
{'hostname': 'xyz', 'ip': '127.0.0.5', 'extra': 'check-it'},
{'hostname': 'abc', 'ip': '127.0.0.1', 'extra': 'check-for'},
{'hostname': 'abc', 'ip': '127.0.0.1', 'extra': 'check-this'},
{'hostname': 'def', 'ip': '127.0.0.2', 'extra': 'check-for'},
{'hostname': 'def', 'ip': '127.0.0.2', 'extra': 'check-this'}]}