【问题标题】:Modifying a nested dictionary修改嵌套字典
【发布时间】:2021-12-13 04:59:23
【问题描述】:

我正在使用正则表达式来查看文件以检查用户名以及他们的操作是否导致错误(错误表示错误,信息表示成功操作) 我使用嵌套字典来跟踪操作,用户名作为主键,嵌套字典记录了它们生成了多少 INFO 和 ERROR 行。

#!/usr/bin/env python3
import re

users = {}
with open('logfile.txt') as f:
    for line in f:
        regex_user = r"(INFO|ERROR): .* \((.+)\)$"
        """searches for users and if there message was info or error"""
        user = re.serach(regex_user, line)
        if user is None:
            continue
        name = user[2]
        cat = user[1]
        try:
            # Method 1?
            users[name][cat] = users[name].get(cat, 0) + 1
            # Method 2?
            users[name][cat] = users.get(name, {}).get(cat, 0) + 1
        except KeyError:
            print("Where are my keys?")

我想知道这两种方法中的哪一种(如果有的话)正确地修改了字典以增加相应嵌套键的计数。

输出应如下所示:

{'John': {'INFO': 22, 'ERROR': 3}}

如果日志包含用户 John 的 22 行 INFO 和 3 行 ERROR。

【问题讨论】:

  • 如果users 没有键name,那么当您尝试分配给users[name][cat] 时,方法2 将产生错误。您可能想查看collections.defaultdict()
  • 如果users没有键name,那么当你尝试获取users[name]的值时方法1会产生错误。因此,如果 name 已经不是 users 中的键,则两者都不起作用。
  • 谢谢,我去看看 collections.defaultdict()

标签: python-3.x dictionary nested


【解决方案1】:

您可能希望使用嵌套的collections.defaultdict 或使用setdefault() 来解决此问题,尽管我认为后者不是干净的。 collections.defaultdict() 将允许您引用一个尚不存在的字典键,这是您问题的症结所在。

尝试类似:

import collections
import json
import random

users = collections.defaultdict(lambda: collections.defaultdict(int))
for i in range(100):
    user = random.choice(["John", "Jane", "Sanjay"])
    cat =  random.choice(["INFO", "ERROR"])
    users[user][cat] += 1

print(json.dumps(users, indent=2))

这将打印出如下内容:

{
  "Jane": {
    "INFO": 16,
    "ERROR": 19
  },
  "John": {
    "ERROR": 21,
    "INFO": 10
  },
  "Sanjay": {
    "INFO": 18,
    "ERROR": 16
  }
}

虽然每次运行都会有所不同。

正如@Ryukashin 所指出的,defaultdict() 不如print() 好于dict()。因此,如果出于某种原因确实需要,则可以退回。最简单(不是最有效)的方式可能是:

users = json.loads(json.dumps(users))

【讨论】:

  • defaultdict( at 0x0000012EB5961240>, {'John': defaultdict(, {'INFO': 2, 'ERROR': 1}), 'Sally ': defaultdict(, {'ERROR': 2, 'INFO': 1}), 'Greg': defaultdict(, {'INFO': 1, 'ERROR': 1}), 'Marge': defaultdict(, {'INFO': 2, 'ERROR': 2})}) 当我尝试使用 collection.defaultdict(lambda: collections.defaultdict (int)) 正如你所拥有的。字典已打印出来,但 lambda 和类 'int' 存在错误
  • 没有实际错误。那就是你看到的“错误”猫。如果您正在做的是print(users),您可能不会想到这一点,因为defaultdict() 的打印效果不如普通的旧dict()。如果出于某种原因您最终确实需要 dict 而不是 defaultdict 作为类型,那么您可以将其全部转换回来。
猜你喜欢
  • 1970-01-01
  • 2018-09-13
  • 1970-01-01
  • 2022-06-19
  • 2019-07-18
  • 2018-07-10
  • 2021-04-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多