やりたいこと
pythonで、辞書が持つvalue同士の直積を、対応するkeyを変えずに辞書としてそれぞれ出力したい。
具体的には
{'A':[1,2,3],'B':[4,5]}
という辞書が存在するときに
[{'A':1,'B':4},{'A':1,'B':5},{'A':2,'B':4},{'A':2,'B':5},{'A':3,'B':4},{'A':3,'B':5}]
といった具合のリストが得られるようにしたい。
前提知識
itertools.product()で直積を求められます。
https://docs.python.org/ja/3/library/itertools.html#itertools.product
実装
test1.py
importitertoolstest1={'A':[1,2,3],'B':[4,5]}product=[xforxinitertools.product(*test1.values())]result=[dict(zip(test1.keys(),r))forrinproduct]forrinresult:print(r)
console
{'A': 1, 'B': 4}
{'A': 1, 'B': 5}
{'A': 2, 'B': 4}
{'A': 2, 'B': 5}
{'A': 3, 'B': 4}
{'A': 3, 'B': 5}
valueの型が異なっていてもOK
test2.py
importitertoolstest2={'A':['TEST',1,2.5],'B':[[3,4],5]}product=[xforxinitertools.product(*test2.values())]result=[dict(zip(test1.keys(),r))forrinproduct]forrinresult:print(r)
console
{'A': 'TEST', 'B': [3, 4]}
{'A': 'TEST', 'B': 5}
{'A': 1, 'B': [3, 4]}
{'A': 1, 'B': 5}
{'A': 2.5, 'B': [3, 4]}
{'A': 2.5, 'B': 5}
注意点
直積を求めたい辞書のvalueはlist型でなければなりません。
例えば以下の様な辞書を変換しようとするとエラーとなります。
test3.py
importitertoolstest3={'A':1,'B':[2,3],'C':[4,5,6]}product=[xforxinitertools.product(*test3.values())]result=[dict(zip(test1.keys(),r))forrinproduct]forrinresult:print(r)
console
Traceback (most recent call last):
File "test3.py", line 5, in <module> product = [x for x in itertools.product(*test1.values())]
TypeError: 'int' object is not iterable
この様な場合は一旦valueを舐めてlistでなければlistに変換してあげれば良いです。
test4.py
importitertoolstest4={'A':1,'B':[2,3],'C':[4,5,6]}test4_after=dict([(key,valiftype(val)islistelse[val])forkey,valintest4.items()])product=[xforxinitertools.product(*test4_after.values())]result=[dict(zip(test4_after.keys(),r))forrinproduct]forrinresult:print(r)
console
{'A': 1, 'B': 2, 'C': 4}
{'A': 1, 'B': 2, 'C': 5}
{'A': 1, 'B': 2, 'C': 6}
{'A': 1, 'B': 3, 'C': 4}
{'A': 1, 'B': 3, 'C': 5}
{'A': 1, 'B': 3, 'C': 6}
key値を捨てる場合
key値を捨ててvalueの直積だけ欲しい場合はzipの部分を消せばOK。
test5.py
importitertoolstest5={'A':[1,2],'B':[4,5,6]}product=[xforxinitertools.product(*test5.values())]forrinproduct:print(r)
console
(1, 4)
(1, 5)
(1, 6)
(2, 4)
(2, 5)
(2, 6)