Hàm python3 để hợp nhất các từ điển

Aug 28 2020

Tôi có một loạt các bản ghi JSON, mỗi bản ghi có mức độ hoàn chỉnh khác nhau. Nói cách khác, bản ghi A có thể chứa các khóa không có trong bản ghi B và ngược lại. Để hiểu rõ hơn về dữ liệu bên trong, tôi đã tạo một hàm lấy N số bản ghi và hợp nhất chúng lại với nhau, tạo một bản ghi frankenstein duy nhất chứa tất cả các khóa và một giá trị duy nhất cho mỗi khóa.

import sys
import json
def frankenstein(out, in_dict, key=None):
    if isinstance(in_dict, dict):
        for k, v in in_dict.items():
            if isinstance(in_dict[k], list) and v:
                out.setdefault(k, [])
                frankenstein(out[k], v, k)
            elif isinstance(in_dict[k], dict) and v:
                out.setdefault(k, {})
                frankenstein(out[k], v, k)
            elif v:
                out[k] = v
    elif isinstance(in_dict, list):
        s = {}
        for item in in_dict:
            if isinstance(item, dict):
                frankenstein(s, item)
            elif not out:
                out.append(item)
            if s:
                if not out:
                    out.append(s)
                else:
                    frankenstein(s, out[0])
                    out[0] = s
if __name__ == '__main__':
    l = [
        {
            "name": "foo bar",
            "experience": [
                {
                    "company": {
                        "name": "oracle",
                        "hq": "123 main st",
                        "size": 100
                    },
                    "function": [
                        {
                            "name": "go getter"
                        }
                    ],
                    "location": {
                        "doubleday": "publisher"
                    },
                    "animal": "horse"
                }
            ],
            "skills": ["programming", "eating"]
        },
        {
            "name": "poo dar",
            "experience": [
                {
                    "company": {
                        "name": "microsoft",
                        "url": "foo.bar/com"
                    },
                    "function": [
                        {
                            "name": "bread",
                            "level": "really high"
                        }
                    ],
                    "solitary": {
                        "fat": "cat"
                    },
                    "health": "no good"
                }
            ],
            "skills": ["igz"]
        },
        {
            "name": "poo mar",
            "experience": [
                {
                    "function": [
                        {
                            "zoo": "creature"
                        }
                    ],
                    "location": {
                        "taste": "food"
                    },
                    "ping": {
                        "pong": "bong"
                    }
                }
            ],
            "skills": ["woots own"]
        }
    ]
    out = {}
    for item in l:
        frankenstein(out, item)
    print(json.dumps(out, indent=4))

Đây là đầu ra từ mã:

{
    "name": "poo mar",
    "experience": [
        {
            "function": [
                {
                    "name": "bread",
                    "level": "really high",
                    "zoo": "creature"
                }
            ],
            "location": {
                "taste": "food",
                "doubleday": "publisher"
            },
            "ping": {
                "pong": "bong"
            },
            "company": {
                "name": "oracle",
                "url": "foo.bar/com",
                "hq": "123 main st",
                "size": 100
            },
            "solitary": {
                "fat": "cat"
            },
            "health": "no good",
            "animal": "horse"
        }
    ],
    "skills": [
        "programming"
    ]
}

Tôi đã thử nghiệm chức năng và nó hoạt động. Điều tôi muốn là một số phản hồi liên quan đến mã. Tôi có đang làm điều này theo cách hiệu quả nhất có thể không? Có cách nào tốt hơn để làm điều đó không?

Trả lời

5 RootTwo Aug 31 2020 at 12:16

Các keytham số để frankenstein()không xuất hiện để được sử dụng bất cứ nơi nào và có thể được loại bỏ.

Sử dụng các dòng trống để chia mã thành các đoạn logic nhỏ hơn. Nó hỗ trợ đọc và hiểu mã.

in_dict là một cái tên gây hiểu lầm, vì nó có thể là một danh sách, mệnh đề hoặc một cái gì đó khác hoàn toàn.

Trong for k, v in in_dict.items():vòng lặp, in_dict[k]vđiều tương tự, vđược kiểm tra 3 lần, và giá trị trả về của setdefault()bị loại bỏ sau đó được tra cứu trên dòng tiếp theo. Nó có thể được viết lại như vậy:

    for k, v in in_dict.items():
        if not v:
            continue

        if isinstance(v, (list, dict)):
            out_k = out.setdefault(k, v.__class__())
            frankenstein(out_k, v)

        else:
            out[k] = v

Logic để xử lý listscó vẻ phức tạp. Ví dụ: có vẻ như scó thể được cập nhật mỗi lần thông qua vòng lặp và cũng được thêm vào out[k]. Câu hỏi không nêu rõ các quy tắc kết hợp mọi thứ, vì vậy có thể nó đúng. Một nhận xét hoặc chuỗi doc giải thích mục đích của hàm và các quy tắc để hợp nhất các giá trị sẽ hữu ích.