基于数组递归修改现有字典

huangapple go评论78阅读模式
英文:

Recursively modifying existing dictionary based on an array

问题

我有以下的输入变量:'PATH',它是一个包含要创建的键的数组,以及'output_content',它是一个字典,应该在其中创建这些键,'output content'已经包含键值对,它们不应该丢失。

例如,考虑PATH = ['patterns', 'pattern_1', 'children', 'pattern_1_1'],结果的'output_content'字典应该如下所示:

{
    'patterns': {
        'pattern_1': {
            'children': {
                'pattern_1_1': {}
            }
        }
    },
    'already_existing_key': 'already_existing_value'
}

我尝试了以下方法:

current_dict = output_content
for key in PATH[1:]:
    if key not in current_dict:
        current_dict[key] = {}
    current_dict = current_dict[key]

但很快我意识到这样做不会起作用,因为output_content根据current_dict在变化,所以最终的输出将只是{}

英文:

I have the the following input variables: 'PATH', which is an array containing keys to create to and 'output_content' which is a dictionary where the keys should be created in, 'output content' already contains key-value pairs, and they should not be lost.
For example: considering PATH = ['patterns', 'pattern_1', 'children', 'pattern_1_1'], the resulting 'output_content' dictionary should look like this:

{
    'patterns': {
        'pattern_1': {
            'children': {
                'pattern_1_1': {}
            }
        }
    },
    'already_existing_key': 'already_existing_value'
}

I've tried the following:

current_dict = output_content
for key in PATH[1:]:
    if key not in current_dict:
        current_dict[key] = {}
    current_dict = current_dict[key]

But soon i realized that the it just wouldn't work because output_content is changing according to current_dict, so the resulting output will be just {}.

答案1

得分: 0

两个关于你的代码的注释
* 你应该遍历整个列表 `PATH`,而不仅仅是 `PATH[1:]`。我看不到跳过第一个元素的理由
* 如果条件 `key in current_dict` 被满足那么你应该确保相关联的值是一个字典

```python3
def add_path_to_dict(d, path):
    for k in path:
        if k not in d:
            d[k] = {}
        elif not isinstance(d[k], dict):
            return
        d = d[k]

d = {'z': 42}
add_path_to_dict(d, 'abcdefgh')
print(d)
# {'z': 42, 'a': {'b': {'c': {'d': {'e': {'f': {'g': {'h': {}}}}}}}}}

d = {'a': {'b': {'c':{'z': 42}}}}
add_path_to_dict(d, 'abcdefgh')
print(d)
# {'a': {'b': {'c': {'z': 42, 'd': {'e': {'f': {'g': {'h': {}}}}}}}}}

d = {'a': {'b': {'c':42}}}
add_path_to_dict(d, 'abcdefgh')
print(d)
# {'a': {'b': {'c': 42}}}

更进一步的建议:

  • 与其使用空的 return,你可以使用 return 'Some error value',或者你可以 raise ValueError(f'Key {k} already in dict and its value is not a dict.')

<details>
<summary>英文:</summary>

Two remarks with your code:
* You should iterate on the whole list `PATH`, not just `PATH[1:]`. I see no reason to skip the first element.
* If the condition `key in current_dict` is realised, then you should make sure that the associated value is a dict.

```python3
def add_path_to_dict(d, path):
    for k in path:
        if k not in d:
            d[k] = {}
        elif not isinstance(d[k], dict):
            return
        d = d[k]

d = {&#39;z&#39;: 42}
add_path_to_dict(d, &#39;abcdefgh&#39;)
print(d)
# {&#39;z&#39;: 42, &#39;a&#39;: {&#39;b&#39;: {&#39;c&#39;: {&#39;d&#39;: {&#39;e&#39;: {&#39;f&#39;: {&#39;g&#39;: {&#39;h&#39;: {}}}}}}}}}

d = {&#39;a&#39;: {&#39;b&#39;: {&#39;c&#39;:{&#39;z&#39;: 42}}}}
add_path_to_dict(d, &#39;abcdefgh&#39;)
print(d)
# {&#39;a&#39;: {&#39;b&#39;: {&#39;c&#39;: {&#39;z&#39;: 42, &#39;d&#39;: {&#39;e&#39;: {&#39;f&#39;: {&#39;g&#39;: {&#39;h&#39;: {}}}}}}}}}

d = {&#39;a&#39;: {&#39;b&#39;: {&#39;c&#39;:42}}}
add_path_to_dict(d, &#39;abcdefgh&#39;)
print(d)
# {&#39;a&#39;: {&#39;b&#39;: {&#39;c&#39;: 42}}}

Further suggestions:

  • Instead of the empty return, you could return &#39;Some error value&#39; or you could raise ValueError(f&#39;Key {k} already in dict and its value is not a dict.&#39;)

答案2

得分: 0

如评论中所指出的,您的代码没有太多问题,只是路径中不必要的 [1:] 切片操作。

如果您想要更加简洁的写法,您可以使用 dict.setdefault 方法,避免需要测试键是否已经存在:

output_content = {'already_existing_key': 'already_existing_value'}
path = ['patterns', 'pattern_1', 'children', 'pattern_1_1']
current_dict = output_content
for key in path:
    current_dict = current_dict.setdefault(key, {})
print(output_content)

演示:https://replit.com/@blhsing/UnusedDiscreteScriptinglanguages

英文:

As pointed out in the comments, there isn't much wrong with your code except the unnecessary [1:] slice of the path.

If you're looking for a more concise way to write the code, you can use the dict.setdefault method to avoid having to test if a key already exists:

output_content = {&#39;already_existing_key&#39;: &#39;already_existing_value&#39;}
path = [&#39;patterns&#39;, &#39;pattern_1&#39;, &#39;children&#39;, &#39;pattern_1_1&#39;]
current_dict = output_content
for key in path:
    current_dict = current_dict.setdefault(key, {})
print(output_content)

Demo: https://replit.com/@blhsing/UnusedDiscreteScriptinglanguages

答案3

得分: 0

答案中的代码如下:

@Stef@blhsing 的两个答案都修改了原始的 `dict`,这可能不是你想要的行为如果你需要一个副本可以尝试以下解决方案

```py
def add_path(path, dict_):
    copied = dict_.copy()
    dict_ = copied
    
    for index, element in enumerate(path):
        dict_ = dict_.setdefault(element, {})
        
        if not isinstance(dict_, dict):
            break
    
    return copied

<details>
<summary>英文:</summary>

Both answers by @Stef and @blhsing modify the original `dict`, a behaviour which you may not want. Here&#39;s another solution if you need a copy:

```py
def add_path(path, dict_):
	copied = dict_.copy()
	dict_ = copied
	
	for index, element in enumerate(path):
		dict_ = dict_.setdefault(element, {})
		
		if not isinstance(dict_, dict):
			break
	
	return copied

huangapple
  • 本文由 发表于 2023年3月15日 17:52:08
  • 转载请务必保留本文链接:https://go.coder-hub.com/75743028.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定