Hướng dẫn merge two dictionaries python without overwrite - hợp nhất hai từ điển python mà không ghi đè

Tôi có một giải pháp nếu bạn muốn có nhiều tự do hơn để lựa chọn khi nào một giá trị nên được ghi đè trong từ điển được hợp nhất. Có thể đó là một kịch bản dài dòng, nhưng không khó để hiểu logic của nó.

Cảm ơn Fabiocaccamo và người gửi đã chia sẻ gói Benedict và logic lặp lại trong danh sách trong danh sách, tương ứng. Kiến thức này là nền tảng cho sự phát triển kịch bản.fabiocaccamo and senderle for sharing the benedict package, and the nested iteration logic in lists, respectively. This knowledge was fundamental to the script development.

Yêu cầu Python

pip install python-benedict==0.24.3

Kịch bản Python

Định nghĩa của lớp Dict.

from __future__ import annotations

from collections.abc import Mapping
from benedict import benedict
from typing import Iterator
from copy import deepcopy


class Dict:
    def __init__[self, data: dict = None]:
        """
        Instantiates a dictionary object with nested keys-based indexing.

        Parameters
        ----------
        data: dict
            Dictionary.

        References
        ----------
        [1] 'Dict' class: //stackoverflow.com/a/70908985/16109419
        [2] 'Benedict' package: //github.com/fabiocaccamo/python-benedict
        [3] Dictionary nested iteration: //stackoverflow.com/a/10756615/16109419
        """
        self.data = deepcopy[data] if data is not None else {}

    def get[self, keys: [object], **kwargs] -> [object, bool]:
        """
        Get dictionary item value based on nested keys.

        Parameters
        ----------
        keys: [object]
            Nested keys to get item value based on.

        Returns
        -------
        value, found: [object, bool]
            Item value, and whether the target item was found.
        """
        data = kwargs.get['data', self.data]
        path = kwargs.get['path', []]
        value, found = None, False

        # Looking for item location on dictionary:
        for outer_key, outer_value in data.items[]:
            trace = path + [outer_key]

            # Getting item value from dictionary:
            if trace == keys:
                value, found = outer_value, True
                break

            if trace == keys[:len[trace]] and isinstance[outer_value, Mapping]:  # Recursion cutoff.
                value, found = self.get[
                    data=outer_value,
                    keys=keys,
                    path=trace
                ]

        return value, found

    def set[self, keys: [object], value: object, **kwargs] -> bool:
        """
        Set dictionary item value based on nested keys.

        Parameters
        ----------
        keys: [object]
            Nested keys to set item value based on.
        value: object
            Item value.

        Returns
        -------
        updated: bool
            Whether the target item was updated.
        """
        data = kwargs.get['data', self.data]
        path = kwargs.get['path', []]
        updated = False

        # Looking for item location on dictionary:
        for outer_key, outer_value in data.items[]:
            trace = path + [outer_key]

            # Setting item value on dictionary:
            if trace == keys:
                data[outer_key] = value
                updated = True
                break

            if trace == keys[:len[trace]] and isinstance[outer_value, Mapping]:  # Recursion cutoff.
                updated = self.set[
                    data=outer_value,
                    keys=keys,
                    value=value,
                    path=trace
                ]

        return updated

    def add[self, keys: [object], value: object, **kwargs] -> bool:
        """
        Add dictionary item value based on nested keys.

        Parameters
        ----------
        keys: [object]
            Nested keys to add item based on.
        value: object
            Item value.

        Returns
        -------
        added: bool
            Whether the target item was added.
        """
        data = kwargs.get['data', self.data]
        added = False

        # Adding item on dictionary:
        if keys[0] not in data:
            if len[keys] == 1:
                data[keys[0]] = value
                added = True
            else:
                data[keys[0]] = {}

        # Looking for item location on dictionary:
        for outer_key, outer_value in data.items[]:
            if outer_key == keys[0]:  # Recursion cutoff.
                if len[keys] > 1 and isinstance[outer_value, Mapping]:
                    added = self.add[
                        data=outer_value,
                        keys=keys[1:],
                        value=value
                    ]

        return added

    def remove[self, keys: [object], **kwargs] -> bool:
        """
        Remove dictionary item based on nested keys.

        Parameters
        ----------
        keys: [object]
            Nested keys to remove item based on.

        Returns
        -------
        removed: bool
            Whether the target item was removed.
        """
        data = kwargs.get['data', self.data]
        path = kwargs.get['path', []]
        removed = False

        # Looking for item location on dictionary:
        for outer_key, outer_value in data.items[]:
            trace = path + [outer_key]

            # Removing item from dictionary:
            if trace == keys:
                del data[outer_key]
                removed = True
                break

            if trace == keys[:len[trace]] and isinstance[outer_value, Mapping]:  # Recursion cutoff.
                removed = self.remove[
                    data=outer_value,
                    keys=keys,
                    path=trace
                ]

        return removed

    def items[self, **kwargs] -> Iterator[object, object]:
        """
        Get dictionary items based on nested keys.

        Returns
        -------
        keys, value: Iterator[object, object]
            List of nested keys and list of values.
        """
        data = kwargs.get['data', self.data]
        path = kwargs.get['path', []]

        for outer_key, outer_value in data.items[]:
            if isinstance[outer_value, Mapping]:
                for inner_key, inner_value in self.items[data=outer_value, path=path + [outer_key]]:
                    yield inner_key, inner_value
            else:
                yield path + [outer_key], outer_value

    @staticmethod
    def merge[dict_list: [dict], overwrite: bool = False, concat: bool = False, default_value: object = None] -> dict:
        """
        Merges dictionaries, with value assignment based on order of occurrence. Overwrites values if and only if:
            - The key does not yet exist on merged dictionary;
            - The current value of the key on merged dictionary is the default value.

        Parameters
        ----------
        dict_list: [dict]
            List of dictionaries.
        overwrite: bool
            Overwrites occurrences of values. If false, keep the first occurrence of each value found.
        concat: bool
            Concatenates occurrences of values for the same key.
        default_value: object
            Default value used as a reference to override dictionary attributes.

        Returns
        -------
        md: dict
            Merged dictionary.
        """
        dict_list = [d for d in dict_list if d is not None and isinstance[d, dict]] if dict_list is not None else []
        assert len[dict_list], f"no dictionaries given."

        # Keeping the first occurrence of each value:
        if not overwrite:
            dict_list = [Dict[d] for d in dict_list]

            for i, d in enumerate[dict_list[:-1]]:
                for keys, value in d.items[]:
                    if value != default_value:
                        for j, next_d in enumerate[dict_list[i+1:], start=i+1]:
                            next_d.remove[keys=keys]

            dict_list = [d.data for d in dict_list]

        md = benedict[]
        md.merge[*dict_list, overwrite=True, concat=concat]

        return md

Định nghĩa của phương pháp main để hiển thị các ví dụ.

import json


def main[] -> None:
    dict_list = [
        {1: 'a', 2: None, 3: {4: None, 5: {6: None}}},
        {1: None, 2: None, 3: {4: 'c', 5: {6: {7: None}}}},
        {1: None, 2: 'b', 3: {4: None, 5: {6: {7: 'd'}}}},
        {1: None, 2: 'b', 3: {4: None, 5: {6: {8: {9: {10: ['e', 'f']}}}}}},
        {1: None, 2: 'b', 3: {4: None, 5: {6: {8: {9: {10: ['g', 'h']}}}}}},
    ]

    d = Dict[data=dict_list[-1]]

    print["Dictionary operations test:\n"]
    print[f"data = {json.dumps[d.data, indent=4]}\n"]
    print[f"d = Dict[data=data]"]

    keys = [11]
    value = {12: {13: 14}}
    print[f"d.get[keys={keys}] --> {d.get[keys=keys]}"]
    print[f"d.set[keys={keys}, value={value}] --> {d.set[keys=keys, value=value]}"]
    print[f"d.add[keys={keys}, value={value}] --> {d.add[keys=keys, value=value]}"]
    keys = [11, 12, 13]
    value = 14
    print[f"d.add[keys={keys}, value={value}] --> {d.add[keys=keys, value=value]}"]
    value = 15
    print[f"d.set[keys={keys}, value={value}] --> {d.set[keys=keys, value=value]}"]
    keys = [11]
    print[f"d.get[keys={keys}] --> {d.get[keys=keys]}"]
    keys = [11, 12]
    print[f"d.get[keys={keys}] --> {d.get[keys=keys]}"]
    keys = [11, 12, 13]
    print[f"d.get[keys={keys}] --> {d.get[keys=keys]}"]
    keys = [11, 12, 13, 15]
    print[f"d.get[keys={keys}] --> {d.get[keys=keys]}"]
    keys = [2]
    print[f"d.remove[keys={keys}] --> {d.remove[keys=keys]}"]
    print[f"d.remove[keys={keys}] --> {d.remove[keys=keys]}"]
    print[f"d.get[keys={keys}] --> {d.get[keys=keys]}"]

    print["\n-----------------------------\n"]
    print["Dictionary values match test:\n"]
    print[f"data = {json.dumps[d.data, indent=4]}\n"]
    print[f"d = Dict[data=data]"]

    for keys, value in d.items[]:
        real_value, found = d.get[keys=keys]
        status = "found" if found else "not found"
        print[f"d{keys} = {value} == {real_value} [{status}] --> {value == real_value}"]

    print["\n-----------------------------\n"]
    print["Dictionaries merge test:\n"]

    for i, d in enumerate[dict_list, start=1]:
        print[f"d{i} = {d}"]

    dict_list_ = [f"d{i}" for i, d in enumerate[dict_list, start=1]]
    print[f"dict_list = [{', '.join[dict_list_]}]"]

    md = Dict.merge[dict_list=dict_list]
    print["\nmd = Dict.merge[dict_list=dict_list]"]
    print["print[md]"]
    print[f"{json.dumps[md, indent=4]}"]


if __name__ == '__main__':
    main[]

Đầu ra

Dictionary operations test:

data = {
    "1": null,
    "2": "b",
    "3": {
        "4": null,
        "5": {
            "6": {
                "8": {
                    "9": {
                        "10": [
                            "g",
                            "h"
                        ]
                    }
                }
            }
        }
    }
}

d = Dict[data=data]
d.get[keys=[11]] --> [None, False]
d.set[keys=[11], value={12: {13: 14}}] --> False
d.add[keys=[11], value={12: {13: 14}}] --> True
d.add[keys=[11, 12, 13], value=14] --> False
d.set[keys=[11, 12, 13], value=15] --> True
d.get[keys=[11]] --> [{12: {13: 15}}, True]
d.get[keys=[11, 12]] --> [{13: 15}, True]
d.get[keys=[11, 12, 13]] --> [15, True]
d.get[keys=[11, 12, 13, 15]] --> [None, False]
d.remove[keys=[2]] --> True
d.remove[keys=[2]] --> False
d.get[keys=[2]] --> [None, False]

-----------------------------

Dictionary values match test:

data = {
    "1": null,
    "3": {
        "4": null,
        "5": {
            "6": {
                "8": {
                    "9": {
                        "10": [
                            "g",
                            "h"
                        ]
                    }
                }
            }
        }
    },
    "11": {
        "12": {
            "13": 15
        }
    }
}

d = Dict[data=data]
d[1] = None == None [found] --> True
d[3, 4] = None == None [found] --> True
d[3, 5, 6, 8, 9, 10] = ['g', 'h'] == ['g', 'h'] [found] --> True
d[11, 12, 13] = 15 == 15 [found] --> True

-----------------------------

Dictionaries merge test:

d1 = {1: 'a', 2: None, 3: {4: None, 5: {6: None}}}
d2 = {1: None, 2: None, 3: {4: 'c', 5: {6: {7: None}}}}
d3 = {1: None, 2: 'b', 3: {4: None, 5: {6: {7: 'd'}}}}
d4 = {1: None, 2: 'b', 3: {4: None, 5: {6: {8: {9: {10: ['e', 'f']}}}}}}
d5 = {1: None, 2: 'b', 3: {4: None, 5: {6: {8: {9: {10: ['g', 'h']}}}}}}
dict_list = [d1, d2, d3, d4, d5]

md = Dict.merge[dict_list=dict_list]
print[md]
{
    "1": "a",
    "2": "b",
    "3": {
        "4": "c",
        "5": {
            "6": {
                "7": "d",
                "8": {
                    "9": {
                        "10": [
                            "e",
                            "f"
                        ]
                    }
                }
            }
        }
    }
}

Làm cách nào để hợp nhất hai từ điển trong Python?

Cách đơn giản nhất để hợp nhất hai từ điển trong Python là bằng cách sử dụng toán tử giải nén [**]. Bằng cách áp dụng toán tử "**" vào từ điển, nó mở rộng nội dung của nó là bộ sưu tập các cặp giá trị khóa.using the unpack operator[**]. By applying the "**" operator to the dictionary, it expands its content being the collection of key-value pairs.

Làm cách nào để hợp nhất hai từ điển có cùng giá trị trong Python?

Python 3.9 đã giới thiệu toán tử hợp nhất [|] trong lớp Dict. Sử dụng toán tử hợp nhất, chúng ta có thể kết hợp từ điển trong một dòng mã duy nhất. Chúng ta cũng có thể hợp nhất các từ điển tại chỗ bằng cách sử dụng toán tử cập nhật [| =].merge operator [|] in the dict class. Using the merge operator, we can combine dictionaries in a single line of code. We can also merge the dictionaries in-place by using the update operator [|=].

Dictionary có cập nhật ghi đè không?

Chụp các giá trị vào từ điển bằng phương thức Update [] Phương thức Từ điển Python cung cấp một phương thức cập nhật [] cho phép chúng tôi nối một từ điển vào từ điển khác.Phương thức Cập nhật [] tự động ghi đè lên các giá trị của bất kỳ khóa hiện có nào với các khóa mới.The update[] method automatically overwrites the values of any existing keys with the new ones.

Làm thế nào để bạn đặt một giá trị trong một từ điển theo cách không ghi đè các giá trị hiện có?

Trong Python, bạn có thể thêm một mục mới vào Dictionary Dict bằng dict_object [key] = new_value.Theo cách này, nếu khóa đã tồn tại, giá trị được cập nhật [ghi đè] với giá trị mới.Bằng cách sử dụng phương thức setDefault [], bạn chỉ có thể thêm các mục với các giá trị mới cho các khóa mới mà không thay đổi giá trị cho các khóa hiện có.By using the setdefault[] method, you can add items with new values only for new keys without changing the values for existing keys.

Bài Viết Liên Quan

Chủ Đề