从嵌套字典中删除基于条件的子CT

2024-05-16 18:29:03 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个嵌套字典,包含“密度”和“温度”的(子)dicts。结构如下:

profiles_dict =

{
    "density": {
        "elements": [
            {
                "layers": [
                    {
                        "top": 54.0,
                        "bottom": 3.75,
                        "value": 218.9
                    }
                ]
            }
        ],
        "type": "density"
    },
    "temperature": {
        "elements": [
            {
                "layers": []
            }
        ],
        "type": "temperature"
    }
}

正如在temperature子ct中可以看到的,“layers”键包含一个空列表作为值。我的目标是创建一个循环/函数来删除字典{"layers": []}

结果应该如下所示:

profiles_dict_new =

{
    "density": {
        "elements": [
            {
                "layers": [
                    {
                        "top": 54.0,
                        "bottom": 3.75,
                        "value": 218.9
                    }
                ]
            }
        ],
        "type": "density"
    },
    "temperature": {
        "elements": [
            ],
        "type": "temperature"
    }
}

我尝试了以下方法:

for k1, v1 in profiles_dict.items():
        for k2, v2 in v1.items():
            if type(v2) != list:
                continue
            for i in v2:
                for k3, v3 in i.items():
                    if v3 == []:
                        del(i)

通过这个循环,我可以访问{'layers': []},但是我不知道如何正确地将它从dictionray中删除

第二种方法基于Ajax1234解决方案(Deleting Items based on Keys in nested Dictionaries in python

profiles_dict_new = {d:{e:[{l:v for l, v in e.items() if v != []}]} for d, e in profiles_dict.items()}
print(profiles_dict_new)

这给了我以下错误:

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-11-126f19ab7afd> in <module>
----> 1 profiles_dict_new = {d:{e:[{l:v for l, v in e.items() if v != []}]} for d, e in profiles_dict.items()}
      2 print(profiles_dict_new)

<ipython-input-11-126f19ab7afd> in <dictcomp>(.0)
----> 1 profiles_dict_new = {d:{e:[{l:v for l, v in e.items() if v != []}]} for d, e in profiles_dict.items()}
      2 print(profiles_dict_new)

TypeError: unhashable type: 'dict'

对于所介绍的任何一种方法,我们都非常感谢您的帮助


Tags: 方法innewforiflayerstypeitems
3条回答

很多文本,但您需要的是从list中删除dict?! 您的列表不是i(列表的元素),而是v2,因此请确保为您的变量起好名字,并将for更改为while,因为在迭代过程中删除可能会导致问题

for k1, v1 in profiles_dict.items():
    for k2, v2 in v1.items():
        if type(v2) != list:
            continue
        i = 0
        while i < len(v2):
            for k3, v3 in v2[i].items():
                if v3 == []:
                    v2.pop(i) #remove k3 if v3 empty from list v2 at index i
                    i -= 1 #decrease index i
                    break #cause k3, v3 in v2[i].items() does not exist anymore
            i += 1

如果list{}中的一个项目dict包含多个不为空的k3,并且您不想将其删除,则可以将空的项目存储在新的list{}中供以后使用。 如果remove_keys包含与整个dict相同的数量,您可以从v2.pop(index)它,否则.pop(key)所有存储的密钥只能从当前dict{}中存储

for k1, v1 in profiles_dict.items():
    for k2, v2 in v1.items():
        if type(v2) != list:
            continue
        i = 0
        while i < len(v2):
            remove_keys = [] #store k3 when v3 == []
            for k3, v3 in v2[i].items():
                if v3 == []:
                    remove_keys.append(k3)
            if len(remove_keys) == len(v2[i]): #if this would remove all keys
                v2.pop(i) #delete whole "empty" dict again...
                i -= 1
            else:
                for k3 in remove_keys: #remove stored keys from dict in v2 at i
                    v2[i].pop(k3)
            i += 1

而不是删除分配空列表

您可以尝试以下代码:

for k1, v1 in profiles_dict.items():
        for k2, v2 in v1.items():
            if type(v2) != list:
                continue
            for i in v2:
                for k3, v3 in i.items():
                    if v3 == []:
                        v1[k2] = []

del不删除对象:它删除名称。如果多个名称引用同一对象,则其他名称将保持不变

取消绑定i循环变量对基础列表不起任何作用,而i只是在下一次迭代中被重新分配。必须删除实际的列表元素v2[index_of_i],才能将其从列表中删除

为了能够安全地执行此操作,您需要替换原始列表或向后迭代列表的副本。您也可以向前迭代,但是索引需要格外小心,以确保它考虑前面删除的元素

其次i.items()上的循环是适得其反的。您不希望找到一个包含某个键且其中包含空列表的词典。您需要一个只有一个键的字典,因此不需要循环

for k1, v1 in profiles_dict.items():
    for k2, v2 in v1.items():
        if type(v2) != list:
            continue
        v1[k2] = [i for i in v2 if len(i) > 1 or next(i.values())]

向后迭代将允许您保留原始列表对象:

for k1, v1 in profiles_dict.items():
    for k2, v2 in v1.items():
        if type(v2) != list:
            continue
        n = len(v2) - 1  # capture before modifying
        for i, e in enumerate(reversed(v2)):
            if len(e) == 1 and not next(iter(e.values()))
                del v2[n - i]

如果向前迭代,则必须复制列表才能正确执行,并对索引进行额外的簿记:

for k1, v1 in profiles_dict.items():
    for k2, v2 in v1.items():
        if type(v2) != list:
            continue
        count = 0
        for i, e in enumerate(v2[:]):
            if len(e) == 1 and not next(iter(e.values()))
                del v2[i - count]
                count += 1

表达式next(iter(...))是一种常见的习惯用法,用于从只有一个元素但无法轻松索引的对象中获取单个元素,如dictset。像pop这样的方法是破坏性的:如果只想检查元素,就必须将其放回原处next(iter(...))允许您查看集合

相关问题 更多 >