return 嵌套字典中所有列表中第 n 个值的字典并保留其他值

return dictionary with nth value in all lists within a nested dictionary and retain other values

我有一本看起来像这样的字典:

dict_in = {'key0': {a: [A, B, C], b: [A, B, C]}, 'key1': {c: [A, B, C], d: [A, B, C]}, 'key2': {e: 0, f: 0}}

我想要一个 returns 相同字典但没有列表的函数(或其他函数)。代替列表的是一个值,它对应于每个列表中的第 n 个值。对于没有相应列表的键,我只希望值保持不变。例如,一些函数是这样的:

nth_val = 2
def take_nth_value_from_lists_in_nested_dict(list_in, nth_val):
    ...things and stuff...
    return dict_out
dict_out = {'key0': {a: B, b: B}, 'key1': {c: B, d: B}, 'key2': {e: 0, f: 0}}

请注意 key2 是如何保持不变的。我不知道如何优雅地做到这一点,所以任何帮助将不胜感激!

你可以试试:

list_in = {'key0': {'a': ['A', 'B', 'C'], 'b': ['A', 'B', 'C']}, 'key1': {'c': ['A', 'B', 'C'], 'd': ['A', 'B', 'C']}, 'key2': {'e': 0, 'f': 0}}
nth = 1
for k,v in list_in.items():
    for k2 in v.keys():
        element = list_in[k][k2]
        if isinstance(element, list):
            list_in[k][k2] = element[nth]
print(list_in)

它returns:

{'key0': {'a': 'B', 'b': 'B'},
 'key1': {'c': 'B', 'd': 'B'},
 'key2': {'e': 0, 'f': 0}}

我会用递归来做:

def take_nth_value_from_lists_in_nested_dict(obj, n: int):
    if isinstance(obj, dict):
        return {k: take_nth_value_from_lists_in_nested_dict(v, n) for k, v in obj.items()}
    if isinstance(obj, list):
        return take_nth_value_from_lists_in_nested_dict(obj[n-1], n)
    return obj
>>> take_nth_value_from_lists_in_nested_dict({'a': ['A', 'B', 'C'], 'b': ['A', 'B', 'C'], 'key1': {'c': ['A', 'B', 'C'], 'd': ['A', 'B', 'C']}, 'key2': {'e': 0, 'f': 0}}, 2)
{'a': 'B', 'b': 'B', 'key1': {'c': 'B', 'd': 'B'}, 'key2': {'e': 0, 'f': 0}}

这应该适用于任意深度的嵌套,包括在列表元素内(例如,如果第 N 个列表元素本身是一个包含更多 dicts/lists 的字典)。

单线解决方案可能如下所示:

list_in = {'key0': {'a': ['A', 'B', 'C'], 'b': ['A', 'B', 'C']}, 'key1': {'c': ['A', 'B', 'C'], 'd': ['A', 'B', 'C']}, 'key2': {'e': 0, 'f': 0}}
nth = 1
list_out = {k: {k2: v2 if not isinstance(v2,list) else v2[nth] \
               for k2,v2 in v.items() } \
               for k,v in list_in.items() }

print list_out
{'key2': {'e': 0, 'f': 0}, 'key1': {'c': 'B', 'd': 'B'}, 'key0': {'a': 'B', 'b': 'B'}}

请注意,我用字符串替换了键和列表的值。

我对你的理解是正确的,你想读出嵌套字典中列表的第 n 个元素,因此需要一个函数来执行此操作。

我解决这个任务的方法是递归的,但在我们深入研究函数的工作方式之前,让我们首先尝试了解我们可以用字典做什么。以下是使用字典时的四种有用方法:
.keys()
.values()
.items()
.update()

test_dict = {'a':1, 'b':2, 'c':3}

# Read out keys
list(test_dict.keys())
>>> ['a', 'b', 'c']

# Read out values
list(test_dict.values())
>>> [1, 2, 3]

# Read out keys and values together
list(test_dict.items())
>>> [('a', 1), ('b', 2), ('c', 3)]

# Update a dictionary with a new key, value pair or overwrite an existing one
test_dict.update({'d':4})
test_dict
>>> {'a': 1, 'b': 2, 'c': 3, 'd': 4}

注意我们用方法 .items():
得到了什么 以键值对作为元组的列表

# I'm a tuple
('something','something else','etc.')

我们可以利用 属性 列表可以用 for 循环迭代,这正是我们在函数开头所需要的。那么让我们开始编码吧:

def nth_element_from_list_in_nested_dict(nested_dict, list_index):
    # Iterate trough a list with tuples
    for key,val in nested_dict.items():

变量 key、val 现在代表各个元组的条目:
根据我们的 test_dict 这将是:

# On the first iteration
key='a'
val=1

# On the second iteration
key='b'
val=2

# and so on...

由于我们假设传递给函数的字典是嵌套的,因此我们要检查变量 val 是否是另一个字典。这可以在 if 语句中完成:

def nth_element_from_list_in_nested_dict(nested_dict, list_index):
    # Iterate trough a list with tuples
    for key,val in nested_dict.items():
    # Check if variable val is another dictionary
    if isinstance(val, dict): 
    # isinstance(val, type: for example dict or list) returns True if val is of specified type

现在是函数的递归部分。只要传递给函数的字典的值是另一个字典,我们就会在函数内再次调用函数,直到值是另一种类型(比如列表!)。因为当我们有一个列表作为值时,我们不需要更深入地挖掘,因为我们已经达到了可以 select 第 n 个元素的值。希望这仍然有意义......让我们继续使用代码:

def nth_element_from_list_in_nested_dict(nested_dict, list_index):
    # Iterate trough a list with tuples
    for key,val in nested_dict.items():
    # Check if variable val is another dictionary
    if isinstance(val, dict):
        nth_element_from_list_in_nested_dict(val, list_index) # calls the function again when val is another dictionary
    elif isinstance(val, list):

当我们找到一个列表值时,我们现在可以用该列表中的第 n 个元素更新这个字典:

def nth_element_from_list_in_nested_dict(nested_dict, list_index):
    # Iterate trough a list with tuples
    for key,val in nested_dict.items():
    # Check if variable val is another dictionary
    if isinstance(val, dict):
        nth_element_from_list_in_nested_dict(val, list_index) # calls the function again when val is another dictionary
    elif isinstance(val, list):
        nested_dict.update({key:val[list_index]}) # updates dictionary with the n-th element from val (when val is of type list)

我们现在要做的就是返回更新后的字典,看看函数是否真的按照您的示例字典的预期进行(我已经在 list_in[= 中替换了您的变量51=] 带有字符串,因为它们尚未定义)

### Input ###
list_in = {'key0': 
           {'a': ['A','B', 'C'], 
            'b': ['A', 'B', 'C']
           }, 
           'key1': 
           {'c': ['A', 'B', 'C'], 
            'd': ['A', 'B', 'C']
           }, 
           'key2': {
               'e': 0, 
               'f': 0,
           }
          }

### Function ###   
def nth_element_from_list_in_nested_dict(nested_dict, list_index):
    #
    for key,val in nested_dict.items():
        if isinstance(val, dict):
            nth_element_from_list_in_nested_dict(val, list_index)
        elif isinstance(val, list):
            nested_dict.update({key:val[list_index]})
    return nested_dict

### Tests ###   
# replace with first element (list_index=0)
to_be_updated = list_in.copy()
nth_element_from_list_in_nested_dict(to_be_updated, 0)
>>> {'key0': {'a': 'A', 'b': 'A'},
     'key1': {'c': 'A', 'd': 'A'},
     'key2': {'e': 0, 'f': 0}}

# replace with third element (list_index=2)
to_be_updated = list_in.copy()
nth_element_from_list_in_nested_dict(to_be_updated, 2)
>>> {'key0': {'a': 'C', 'b': 'C'},
     'key1': {'c': 'C', 'd': 'C'},
     'key2': {'e': 0, 'f': 0}}

原来是一个很长的解释,也许有些部分(比如函数中的递归部分)很难理解。此外,当列表长度不同时,此函数容易出错。 尽管如此,我希望这可以帮助您和其他人取得进步;)