ネストされた辞書を展開して平坦にします。例えばJSONをCSVに保存する際にネスト状態を解除して平坦化したい場合に利用してください。
親キーと子キーを.
で連結しています。また、子がリストの場合は親キーに1から始まる連番を付けています。
# 辞書の項目を累積的に処理する
def dict_accumulate(dct, f, acc = {}):
for k, v in dct.items():
acc = f(acc, k, v)
return acc
# リストの項目を累積的に処理する
def list_accumulate(lst, f, acc = {}):
for i, v in enumerate(lst):
acc = f(acc, i, v)
return acc
# 辞書に辞書をマージして返す
# ex. {'a': 1}, {'b': 2} -> {'a': 1, 'b': 2}
def update(dct, append):
dct.update(append)
return dct
# 入れ子の辞書を展開する
# ex. {'a': {'b': 1}} -> {'a.b': 1}
# ex. {'a': [{'b': 1}, {'b': 2}]} -> {'a1.b': 1, 'a2.b': 2}
def flatten(arg, prefix=''):
if isinstance(arg, dict):
return dict_accumulate(arg, lambda acc, k, v: update(acc, flatten(v, prefix + k + '.')))
elif isinstance(arg, list):
return list_accumulate(arg, lambda acc, i, v: update(acc, flatten(v, prefix[:-1] + str(i + 1) + '.')))
else:
return {prefix[:-1]: arg}
使用例
import json
str_json = '{ "users": [ { "_id": 1, "name": "Claudette Bauer", "gender": "female", "age": 36 }, { "_id": 4, "name": "Catalina Robbins", "gender": "female", "age": 29 }, { "_id": 1, "name": "Sloan Macdonald", "gender": "male", "age": 20 } ]}'
obj_json = json.loads(str_json)
flattened = flatten(obj_json)
print(flattened) # {'users1._id': 1, 'users1.name': 'Claudette Bauer', 'users1.gender': 'female', 'users1.age': 36, 'users2._id': 4, 'users2.name': 'Catalina Robbins', 'users2.gender': 'female', 'users2.age': 29, 'users3._id': 1, 'users3.name': 'Sloan Macdonald', 'users3.gender': 'male', 'users3.age': 20}