如果键在其他地方显示为值,则从嵌套字典中删除键

时间:2019-03-26 14:01:20

标签: python python-2.7 dictionary nested

我有一个嵌套的字典,其中包含父母(键)和他们的孩子(值)。如果父级是树中另一个父级的子级,我想删除父级及其子级,即,如果键在字典中的其他位置作为值出现,我想删除它。这是示例输入/输出:

输入:

{
    "Animal":  {
        "Cat":  [],  
        "Dog":  {
            "Labrador":  {
                "LabradorPup":  []
            }
        }
    },  
    "DieselCar":  {
        "Hyundai":  []
    },  
    "Dog":  {
        "Labrador":  {
            "LabradorPup":  []
        }
    },  
    "ElectricCar":  {
        "Tesla":  []
    },  
    "Labrador":  {
        "LabradorPup":  []
    },  
    "PetrolCar":  {
        "Ford":  [],  
        "Hyundai":  []
    },  
    "Vehicle":  {
        "DieselCar":  {
            "Hyundai":  []
        },  
        "ElectricCar":  {
            "Tesla":  []
        },  
        "PetrolCar":  {
            "Ford":  [],  
            "Hyundai":  []
        }
    }
}

所需的输出:

{
    "Animal":  {
        "Cat":  [],  
        "Dog":  {
            "Labrador":  {
                "LabradorPup":  []
            }
        }
    },  
    "Vehicle":  {
        "DieselCar":  {
            "Hyundai":  []
        },  
        "ElectricCar":  {
            "Tesla":  []
        },  
        "PetrolCar":  {
            "Ford":  [],  
            "Hyundai":  []
        }
    }
}

我有以下代码保留有孩子的父母,但这不会产生我想要的输出:

inheritance_tree = {parent:children for parent, children in inheritance_tree.items() if any(child for child in children.values())}

您可以看到"Dog"密钥虽然是"Animal"的子代,但并未删除:

{
    "Animal":  {
        "Cat":  [],  
        "Dog":  {
            "Labrador":  {
                "LabradorPup":  []
            }
        }
    },  
    "Dog":  {
        "Labrador":  {
            "LabradorPup":  []
        }
    },  
    "Vehicle":  {
        "DieselCar":  {
            "Hyundai":  []
        },  
        "ElectricCar":  {
            "Tesla":  []
        },  
        "PetrolCar":  {
            "Ford":  [],  
            "Hyundai":  []
        }
    }
}

3 个答案:

答案 0 :(得分:1)

我认为any(child for child in children.values())不是确定children是否应保留在最终决定中的有效方法。该表达式基本上等于“此字典是否至少有一个不是空字符串的值?”。 Dog dict有一个非空子,因此保留在您的最终dict中。

这是我要使用的方法。编写一个函数,该函数以递归方式遍历嵌套的数据结构并产生所有键,无论它们嵌套的深度如何。在每个顶级键值对上运行此函数,以标识所有子值的名称。然后创建一个新的字典,从顶层将这些名称排除在外。

def iter_all_keys(obj):
    if not isinstance(obj, dict):
        return
    for key, value in obj.items():
        yield key
        for x in iter_all_keys(value):
            yield x

d = {
    "Animal":  {
        "Cat":  [],  
        "Dog":  {
            "Labrador":  {
                "LabradorPup":  []
            }
        }
    },  
    "DieselCar":  {
        "Hyundai":  []
    },  
    "Dog":  {
        "Labrador":  {
            "LabradorPup":  []
        }
    },  
    "ElectricCar":  {
        "Tesla":  []
    },  
    "Labrador":  {
        "LabradorPup":  []
    },  
    "PetrolCar":  {
        "Ford":  [],  
        "Hyundai":  []
    },  
    "Vehicle":  {
        "DieselCar":  {
            "Hyundai":  []
        },  
        "ElectricCar":  {
            "Tesla":  []
        },  
        "PetrolCar":  {
            "Ford":  [],  
            "Hyundai":  []
        }
    }
}

child_names = {child_name for toplevel_name, toplevel_children in d.items() for child_name in iter_all_keys(toplevel_children)}

d = {key: value for key, value in d.items() if key not in child_names}
print(d)

结果(为清楚起见,我添加了空格)

{
    'Animal': {
        'Dog': {
            'Labrador': {
                'LabradorPup': []
            }
        }, 
        'Cat': []
    }, 
    'Vehicle': {
        'DieselCar': {
            'Hyundai': []
        }, 
        'PetrolCar': {
            'Hyundai': [], 
            'Ford': []
        }, 
        'ElectricCar': {
            'Tesla': []
        }
    }
}

请注意,这只会从顶层删除重复项。如果要在这样的字典上运行此代码:

d = {
    "Human":{
        "Fred": [],
        "Barney": []
    },
    "Caveman":{
        "Fred": [],
        "Barney": []
    }
}

...然后,结果字典将与输入相同。 Fred和Barney在数据结构中都出现两次。如果这不是期望的结果,则不清楚结果应该是什么。应当从人类还是穴居人中移除弗雷德和巴尼?如果逻辑应该是“保持Fred和Barney in Human,因为这是我们首先遇到的逻辑。请摆脱其余的逻辑”,那么结果将不是确定性的,因为不能保证2.7中的字典是有序的。

答案 1 :(得分:1)

inheritance_tree = {
parent:children for parent, children in inheritance_tree.items() if any(
    child for child in children.values()
    )
}

任何人都要检查孩子是否有自己的孩子。 因此,您当前的代码所做的只是保留有孙子的父母。 如果要从列表中删除这些子级,可以编写一个遍历列表的函数,并修改其副本。

如果您希望坚持使用一根衬纸,则需要在继承树的值中查找父项。 但是,这些值可能不同于字典,因此您也需要检查该值。

y= {parent:children for parent, children in x.items() if all(
[(parent not in set(k.keys())) for k in x.values() if k])
}

答案 2 :(得分:0)

尝试一下:

我知道它很复杂。

aa = [i for i,j in a.items()]
bb = [get_all_keys(j) for i,j in a.items()]

for i in aa:
    for j in bb:
        if i in j:
            for k in a:
                if k==i:
                    del a[k]

告诉我你是对还是错。