首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >合并两个嵌套对象列表

合并两个嵌套对象列表
EN

Stack Overflow用户
提问于 2022-05-19 22:39:49
回答 1查看 197关注 0票数 0

我想要合并两个嵌套的对象,以便第二个被放置在第一个的顶部。这是针对kubectl配置yaml的,但是它可以是任何嵌套对象,这些对象具有listdict和简单数据类型的组合。例:

代码语言:javascript
复制
# yaml 1:
containers:
  - volumeMounts:
      - name: external-stroage-1
        mountPath: /mnt/stroage_1
        readOnly: true
代码语言:javascript
复制
# Yaml 2
containers:
  - name: cron
    volumeMounts:
      - name: internal-storage
        mountPath: /mnt/data

合并的对象是:

代码语言:javascript
复制
containers:
  - name: cron
  - volumeMounts:
      - name: external-stroage-1
        mountPath: /mnt/stroage_1
        readOnly: true
      - name: internal-storage
        mountPath: /mnt/data

到目前为止,我得到的是:

代码语言:javascript
复制
def merge(object_one, object_two):
    assert type(object_one) == type(object_two), "Mismatched types"

    if isinstance(object_one, dict):
        for key in object_two:
            if key in object_one:
                object_one[key] = merge(object_one[key], object_two[key])
            else:
                object_one[key] = object_two[key]
    elif isinstance(object_one, list):
        for item in object_two:
            object_one.append(item) # <<<<< when should I overwrite instead of append?
    else:
        return object_two

    return object_one

其中大部分都可以通过简单的递归来完成。由于项目是由键索引的,因此很容易识别应该将项插入到dict中的位置。但是,如果有对象的list (如果列表顺序不一定是相同的),那么如何识别两个项是否应该合并?换句话说,我如何确定列表中的某一项是否需要覆盖vs附加?就目前情况而言,所有列表项都会被追加,从而导致错误的合并:

代码语言:javascript
复制
containers:
  - volumeMounts:
      - name: external-stroage-1
        mountPath: /mnt/stroage_1
        readOnly: true
      - name: external-stroage-2
        mountPath: /mnt/stroage_2
  - name: cron
    volumeMounts:  # This item should have been merged instead of being repeated
      - name: internal-storage
        mountPath: /mnt/data
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-05-20 17:59:20

这最终比我所希望的要臃肿一些,并且必须对yaml结构做一个很大的假设,即假设一个列表中的两个dict项是相同的项,如果它们有一个name键和匹配值(这在我们的kubectl yamls中是常见的)。但有了这个假设,这就完成了这个任务:

代码语言:javascript
复制
def merge(object_one, object_two):
    """
    Recursively merge object_two over object one. This is not universal and makes some assumptions based on typical structure of kubectl/plato yamls
    """
    assert type(object_one) == type(object_two), f"Mismatched types for object_one '{object_one}' and object_two {object_two}"

    if isinstance(object_one, dict):
        # If two dicts have a "name" field, and they match, its assumed they are the same field
        if 'name' in object_one.keys() and 'name' in object_two.keys():
            if object_one['name'] == object_two['name']:
                return object_two

        # Add missing keys to object_one
        object_one = {**object_one, **{k: v for k, v in object_two.items() if k not in object_one}}
        found = []

        # If
        for key in {x for x in object_one if x in object_two}:
            if (tmp := merge(object_one[key], object_two[key])) is not None:
                object_one[key] = tmp
                found.append(True)
            else:
                found.append(False)

        # If none is returned, the object is merged from 1 level up
        if not all(found):
            return None

    elif isinstance(object_one, list):
        # Compare every list element against the 2nd object, if no match is found, return None
        for index_two in range(len(object_two)):
            found = []
            for index in range(len(object_one)):
                try:
                    if tmp := merge(object_one[index], object_two[index_two]):
                        object_one[index] = tmp
                        found.append(True)
                    else:
                        found.append(False)
                except Exception:
                    pass

            # If None is returned, the object is merged from 1 level up
            if not any(found):
                object_one.append(object_two[index_two])
    else:
        # If both objects dont' match, return None which signals to the previous stack to merge one level up
        if object_one == object_two:
            return object_one
        return 

    return object_one
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72311793

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档