如果满足条件,则python在嵌套字典中更改值

时间:2016-05-06 15:15:39

标签: python dictionary iterator

我知道之前已经提出过类似的问题,但是我在为我的特殊情况实施这些问题确实存在问题:

假设我有一本不同深度的字典,例如:

dicti = {'files':
    {'a':{'offset':100, 'start': 0}, 
     'b':{
         'c':{'offset':50, 'start':0}
         'd':{'offset':70, 'start':0}  
         }
     'e':{
         'f':{'offset':80, 'start':0}
         'g':{'offset':30, 'start':0}  
         'h':{'offset':20, 'start':0}   
         } 
    }
        }
   etc... (with a lot more different levels and entries)

所以现在我想要一个具有基本相同结构和键的字典的副本,但是如果'offset'(在任何级别)大于我们应该更改50 'offset'0

我猜某种迭代函数会是最好的,但是我无法理解......

4 个答案:

答案 0 :(得分:2)

递归解决方案将更加直观。你想要类似下面的伪代码:

def copy(dict):
    new_dict = {}
    for key, value in dict:
        if value is a dictionary:
            new_dict[key] = copy(value)
        else if key == 'offset' and value > 50:
            new_dict[key] = 0
        else:
            new_dict[key] = value
    return new_dict

答案 1 :(得分:2)

您可以使用标准机制进行复制,然后修改复制的字典(我的示例中的解决方案#1),或者您可以在同一个函数中进行复制和修改(解决方案#2)。

在任何一种情况下,您都在寻找递归函数。

import copy
from pprint import pprint
dicti = {'files':
    {'a':{'offset':100, 'start': 0},
     'b':{
         'c':{'offset':50, 'start':0},
         'd':{'offset':70, 'start':0},
         },
     'e':{
         'f':{'offset':80, 'start':0},
         'g':{'offset':30, 'start':0},
         'h':{'offset':20, 'start':0},
         }
    }
}

# Solution 1, two passes
def modify(d):
    if isinstance(d, dict):
        if d.get('offset', 0) > 50:
            d['offset'] = 0
        for k,v in d.items():
            modify(v)
dictj = copy.deepcopy(dicti)
modify(dictj)
pprint(dictj)

# Solution 2, copy and modify in one pass
def copy_and_modify(d):
    if isinstance(d, dict):
        d2 = {k:copy_and_modify(v) for k,v in d.items()}
        if d2.get('offset') > 50:
            d2['offset'] = 0
        return d2
    return d
dictj = copy_and_modify(dicti)
pprint(dictj)

答案 2 :(得分:1)

d = {'files':
    {'a':{'offset':100, 'start': 0},
     'b':{
         'c':{'offset':50, 'start':0},
         'd':{'offset':70, 'start':0}
         },
     'e':{
         'f':{'offset':80, 'start':0},
         'g':{'offset':30, 'start':0},
         'h':{'offset':20, 'start':0}
         }
    }
        }

def transform(item):
    new_item = item.copy()  # consider usage of deepcopy if needed
    if new_item['offset'] == 80:
        new_item['offset'] = 'CHANGED'
    return new_item

def visit(item):
    if item.get('offset'):
        return transform(item)
    else:
        return {k: visit(v) for k, v in item.items()}

result = visit(d)
print(result)

输出:

{
    'files': {
        'b': {
            'd': {
                'offset': 70,
                'start': 0
            },
            'c': {
                'offset': 50,
                'start': 0
            }
        },
        'e': {
            'g': {
                'offset': 30,
                'start': 0
            },
            'h': {
                'offset': 20,
                'start': 0
            },
            'f': {
                'offset': 'CHANGED',
                'start': 0
            }
        },
        'a': {
            'offset': 100,
            'start': 0
        }
    }
}

您可以修改一些关于答案中使用的内容的链接:

答案 3 :(得分:0)

一旦满足条件,您可以调用递归函数来更改其值:

dicti = {'files':
    {'a':{'offset':100, 'start': 0}, 
     'b':{
         'c':{'offset':50, 'start':0},
         'd':{'offset':70, 'start':0}  
         },
     'e':{
         'f':{'offset':80, 'start':0},
         'g':{'offset':30, 'start':0},  
         'h':{'offset':20, 'start':0}   
         } 
    }
}


def dictLoop(dt):
    for k, v in dt.items():
        if isinstance(v, int):
            if k == 'offset' and v > 50:
                dt[k] = 0
        else: dictLoop(v)
    return dt

print dictLoop(dicti)