如何将新值附加到字典列表中的同一个键?

2024-09-28 01:29:17 发布

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

我有一个测试失败列表,如下所示-

all_failures = [
            'test1/path/to/test1/log/failure_reason1',
            'test1/path/to/test1/log/failure_reason2',
            'test2/path/to/test2/log/failure_reason1',
            'test2/path/to/test2/log/failure_reason2',
            'test3/path/to/test3/log/failure_reason1',
            'test4/path/to/test4/log/failure_reason1',
        ]

我试图通过解析列表中的每个失败来构造一个类似JSON的对象。到目前为止,我已尝试编写以下代码-

for failure in all_failures:
    data = failure.split('/',1)
    test = data[0]
    failure_details_dict[test] = []

    data = '/' + data[1]
    data = data.rsplit('/', 1)

    test_details_dict['path'] = data[0] + '/'
    test_details_dict['reason'] = data[1]

    failure_details_dict[test].append(test_details_dict)

    test_details_dict = {}  

for key,value in failure_details_dict.items():
    print(key)
    print(value)
    print()

我得到的结果是-

test4
[{'reason': 'failure_reason1', 'path': '/path/to/test4/log/'}]

test3
[{'reason': 'failure_reason1', 'path': '/path/to/test3/log/'}]

test1
[{'reason': 'failure_reason2', 'path': '/path/to/test1/log/'}]

test2
[{'reason': 'failure_reason2', 'path': '/path/to/test2/log/'}]

鉴于,预期产出为-

{
    "test1": [
                {
                    "path": "/path/to/test1/log/",
                    "reason": "failure_reason1" 
                },
                {
                    "path": "/path/to/test1/log/",
                    "reason": "failure_reason2"     
                }

            ],
    "test2": [
                {
                    "path": "/path/to/test2/log/",
                    "reason": "failure_reason1" 
                },
                {
                    "path": "/path/to/test2/log/",
                    "reason": "failure_reason2"     
                }
            ],
    "test3": [
                {
                    "path": "/path/to/test3/log/",
                    "reason": "failure_reason1" 
                },
            ],
    "test4": [
                {
                    "path": "/path/to/test4/log/",
                    "reason": "reason1" 
                },
            ]
}

如我们所见,我无法将第二个路径失败原因添加到同一个键中。示例-test1和test2有两个失败原因

有人能帮我理解我遗漏了什么吗?谢谢大家!


Tags: topathtestlogdatafailuredetailsdict
2条回答

您可以使用正则表达式从故障日志文件名中提取信息。这可以通过以下方式简单实现:

import re
import json

all_failures = [
            'test1/path/to/test1/log/failure_reason1',
            'test1/path/to/test1/log/failure_reason2',
            'test2/path/to/test2/log/failure_reason1',
            'test2/path/to/test2/log/failure_reason2',
            'test3/path/to/test3/log/failure_reason1',
            'test4/path/to/test4/log/failure_reason1',
        ]


info = dict()
for failure in all_failures:
    match = re.search(r"^(.*?)(/.*/)(.*)$", failure)

    details = dict()
    details["path"] = match.group(2)
    details["reason"] = match.group(3)

    if match.group(1) in info:
        info[match.group(1)].append(details)
    else:
        info[match.group(1)] = []
        info[match.group(1)].append(details)

print(json.dumps(info, indent=4))

输出:

{
    "test1": [
        {
            "path": "/path/to/test1/log/",
            "reason": "failure_reason1"
        },
        {
            "path": "/path/to/test1/log/",
            "reason": "failure_reason2"
        }
    ],
    "test2": [
        {
            "path": "/path/to/test2/log/",
            "reason": "failure_reason1"
        },
        {
            "path": "/path/to/test2/log/",
            "reason": "failure_reason2"
        }
    ],
    "test3": [
        {
            "path": "/path/to/test3/log/",
            "reason": "failure_reason1"
        }
    ],
    "test4": [
        {
            "path": "/path/to/test4/log/",
            "reason": "failure_reason1"
        }
    ]
}

理由

对于每个循环,您都将覆盖到failure_details_dict[test]


解决方案

您应该只将列表设置为一次。
您有多种选择

  • 非肾盂法(不推荐使用
if test not in failure_details_dict:
    failure_details_dict[test] = []
  • 将赋值替换为dict.setdefault调用。这种方式不会影响与failure_details_dict的其他交互
failure_details_dict.setdefault(test, [])  # instead of failure_details_dict[test] = []
  • collections.defaultdict代替dict。这种方式将影响与failure_detilas_dict的其他交互
from collections import defaultdict

failure_details_dict = defaultdict(list)  # instead of {}

范例

我已经重构了你的代码:

all_failures = [
    'test1/path/to/test1/log/failure_reason1',
    'test1/path/to/test1/log/failure_reason2',
    'test2/path/to/test2/log/failure_reason1',
    'test2/path/to/test2/log/failure_reason2',
    'test3/path/to/test3/log/failure_reason1',
    'test4/path/to/test4/log/failure_reason1',
]

failure_details_dict = {}

for failure in all_failures:
    key, *paths, reason = failure.split('/')
    failure_details_dict.setdefault(key, []).append({
        'path': f"/{'/'.join(paths)}/",
        'reason': reason,
    })

for key, value in failure_details_dict.items():
    print(key)
    print(value)
    print()

结论

  • 如果您想要一个简单的更改,请使用dict.setdefault方法
  • 如果对failure_details_dict有多个访问,并且希望每个访问都有默认值,请使用collection.defaultdict

额外的

How can we modify the code so that 'path' key is copied only once and only multiple dictionaries with 'reason' key is created? In general, what would be the best way to store the data in JSON format?

您可以重新格式化JSON,如:

{
  "test1": {
    "path": "/path/to/test1/log/",
    "reason": [
      "failure_reason1",
      "failure_reason2"
    ]
  },
  "test2": {
    "path": "/path/to/test2/log/",
    "reason": [
      "failure_reason1",
      "failure_reason2"
    ]
  },
  "test3": {
    "path": "/path/to/test3/log/",
    "reason": [
      "failure_reason1"
    ]
  },
  "test4": {
    "path": "/path/to/test4/log/",
    "reason": [
      "reason1"
    ]
  }
}

从代码:

all_failures = [
    'test1/path/to/test1/log/failure_reason1',
    'test1/path/to/test1/log/failure_reason2',
    'test2/path/to/test2/log/failure_reason1',
    'test2/path/to/test2/log/failure_reason2',
    'test3/path/to/test3/log/failure_reason1',
    'test4/path/to/test4/log/failure_reason1',
]

failure_details_dict = {}

for failure in all_failures:
    key, *paths, reason = failure.split('/')
    failure_details_dict.setdefault(key, {
        'path': f"/{'/'.join(paths)}/",
        'reason': [],
    })['reason'].append(reason)

for key, value in failure_details_dict.items():
    print(key)
    print(value)
    print()

相关问题 更多 >

    热门问题