将嵌套字典与嵌入在列表中的字典(函数式 Python)平展



这个问题已经被问了很多次 - 但只有一次在这种特殊情况下,我可以在这里部分找到答案,但它扁平化到每个对象。

我有这本字典:

{'address': {'address_line_1': 'Floor Dekk House',
  'address_line_2': 'Zippora Street Providence Industrial Estate',
  'country': 'Seychelles',
  'locality': 'Mahe',
  'premises': '1st'},
 'address_snippet': '1st, Floor Dekk House, Zippora Street Providence Industrial Estate, Mahe, Seychelles',
 'appointment_count': 1,
 'description': 'Total number of appointments 1',
 'description_identifiers': ['appointment-count'],
 'kind': 'searchresults#officer',
 'links': {'self': '/officers/z7s5QUnhlYpAT8GvqvJ5snKmtHE/appointments'},
 'matches': {'snippet': [], 'title': [1, 8, 10, 11]},
 'snippet': '',
 'title': 'ASTROCOM AG '}

如您所见,"description_identifiers" "matches.title" have a list as value. I'd like to edit my code below to flatten my dictionary so that the json is flattened in a"matches.snippet"以及 {key:value, key:value, key:value}' 对 - 但如果值是原子对象列表(不是列表列表或字典列表(,则该值将维护为列表。

目标是能够将这个 json 上传到 postgresql。

这是我在网上找到的一些代码:

def flatten_json(dictionary):
    """Flatten a nested json file"""
    def unpack(parent_key, parent_value):
        """Unpack one level of nesting in json file"""
        # Unpack one level only!!!
        if isinstance(parent_value, dict):
            for key, value in parent_value.items():
                temp1 = parent_key + '_' + key
                yield temp1, value
        elif isinstance(parent_value, list):
            i = 0 
            for value in parent_value:
                temp2 = parent_key + '_' +str(i) 
                i += 1
                yield temp2, value
        else:
            yield parent_key, parent_value    

    # Keep iterating until the termination condition is satisfied
    while True:
        # Keep unpacking the json file until all values are atomic elements (not dictionary or list)
        dictionary = dict(chain.from_iterable(starmap(unpack, dictionary.items())))
        # Terminate condition: not any value in the json file is dictionary or list
        if not any(isinstance(value, dict) for value in dictionary.values()) and 
           not any(isinstance(value, list) for value in dictionary.values()):
            break
    return dictionary

期望输出:

为了测试,这个字典:不应该是(这就是我现在得到的(:

{'address_address_line_1': 'Floor Dekk House',
 'address_address_line_2': 'Zippora Street Providence Industrial Estate',
 'address_country': 'Seychelles',
 'address_locality': 'Mahe',
 'address_premises': '1st',
 'address_snippet': '1st, Floor Dekk House, Zippora Street Providence Industrial Estate, Mahe, Seychelles',
 'appointment_count': 1,
 'description': 'Total number of appointments 1',
 'description_identifiers_0': 'appointment-count',
 'kind': 'searchresults#officer',
 'links_self': '/officers/z7s5QUnhlYpAT8GvqvJ5snKmtHE/appointments',
 'matches_title_0': 1,
 'matches_title_1': 8,
 'matches_title_2': 10,
 'matches_title_3': 11,
 'snippet': '',
 'title': 'ASTROCOM AG '}

而是

{'address_address_line_1': 'Floor Dekk House',
 'address_address_line_2': 'Zippora Street Providence Industrial Estate',
 'address_country': 'Seychelles',
 'address_locality': 'Mahe',
 'address_premises': '1st',
 'address_snippet': '1st, Floor Dekk House, Zippora Street Providence Industrial Estate, Mahe, Seychelles',
 'appointment_count': 1,
 'description': 'Total number of appointments 1',
 'description_identifiers_0': 'appointment-count',
 'kind': 'searchresults#officer',
 'links_self': '/officers/z7s5QUnhlYpAT8GvqvJ5snKmtHE/appointments',
 'matches_title': [1, 8, 10, 11]
 'snippet': '',
 'title': 'ASTROCOM AG '}

你几乎完成了,除了你需要对条件进行更多的检查:

def flatten(dict_, prefix):
    for k, v in dict_.items():
        if isinstance(v, list) and len(v)==1:
            if isinstance(v[0], dict):
                for key, value in flatten(v[0], prefix+k+"_"):
                    yield key, value
            else:
                yield prefix+k+"_0", v[0]
        elif isinstance(v, dict):
            for key, value in flatten(v, prefix+k+"_"):
                yield key, value
        else:
            yield prefix+k, v

用法:

dict_ = {'address': {'address_line_1': 'Floor Dekk House',
  'address_line_2': 'Zippora Street Providence Industrial Estate',
  'country': 'Seychelles',
  'locality': 'Mahe',
  'premises': '1st'},
 'address_snippet': '1st, Floor Dekk House, Zippora Street Providence Industrial Estate, Mahe, Seychelles',
 'appointment_count': 1,
 'description': 'Total number of appointments 1',
 'description_identifiers': ['appointment-count'],
 'kind': 'searchresults#officer',
 'links': {'self': '/officers/z7s5QUnhlYpAT8GvqvJ5snKmtHE/appointments'},
 'matches': {'snippet': [], 'title': [1, 8, 10, 11]},
 'snippet': '',
 'title': 'ASTROCOM AG '}
import json
print(json.dumps(dict(list(flatten(dict_, ""))), indent=4))

输出:

{
    "address_address_line_1": "Floor Dekk House",
    "address_address_line_2": "Zippora Street Providence Industrial Estate",
    "address_country": "Seychelles",
    "address_locality": "Mahe",
    "address_premises": "1st",
    "address_snippet": "1st, Floor Dekk House, Zippora Street Providence Industrial Estate, Mahe, Seychelles",
    "appointment_count": 1,
    "description": "Total number of appointments 1",
    "description_identifiers_0": "appointment-count",
    "kind": "searchresults#officer",
    "links_self": "/officers/z7s5QUnhlYpAT8GvqvJ5snKmtHE/appointments",
    "matches_snippet": [],
    "matches_title": [
        1,
        8,
        10,
        11
    ],
    "snippet": "",
    "title": "ASTROCOM AG "
}

最新更新