首页 > 解决方案 > Python:如何将值添加到键和键到 dicts

问题描述

我想要一个系统,将不同的命令分配给不同的类别!

这就是我们获取命令的方式:

commands = []
for k, v in config['commands'].items():
    commands.append(config['commands'][k]['command'])

有一个 .yaml 文件,其中每个命令都有不同的属性。一个命令和一个类别:

command_one:
    category: "Information"
    command: "info"
command_two:
    category: "Owneronly"
    command: "ban"
command_two:
    category: "Owneronly"
    command: "kick"

现在我想根据它们在一个集合中的类别对命令进行排序,如下所示:

sortedCommands = {"Owneronly": ["ban", "kick"], "Information": ["info"]}

编辑:您可以从命令中获取类别,如下所示:

for k, v in config['commands'].items():
        commands.append(config['commands'][k]['category'])

标签: pythondictionary

解决方案


这是一种有点冗长(为了清楚起见)的方法:

commands_by_category = {}  # Initialize a dictionary 
for command in config['commands'].items():  # for each block
    category = command.get('category')  # unpack categoy
    cmd = command.get('cmd')  # unpack command
    cmds = commands_by_category.get(category, [])  # Get the current list, or a default empty list
    cmds.append(cmd)  # Append to list. 
    commands_by_category[category] = cmds  # Reassign back to the dict

注意:append()在列表上工作就地,所以你必须拉出当前列表,附加,然后重新分配它。

另一个更简洁的选择是分组行为:

from itertools import groupby
from typing import Callable, Iterable

def group_by(iterable: Iterable, key: Callable) -> dict:
    return {r[0]: list(r[1]) for r in groupby(sorted(iterable, key=key), key)}

group_by(config['commands'].items(), lambda x: x.get("category"))

这需要一些时间来解包,但这是它正在做的事情:

  • sorted()使用决定排序顺序的函数对可迭代对象进行排序。
  • 此处提供的函数是lambda获取类别值的函数。这自然是按字母数字排序的。
  • 然后使用groupby相同的“键”功能进行分组。
  • 排序和分组后,对于结果迭代中的每个项目,将类别指定为键,将结果列表指定为新字典中的值。

这里有一个小问题,因为它返回每个原始项目的完整字典,所以我们必须清除一些信息:

sorted_commands = group_by(config['commands'].items(), lambda x: x.get("category"))
commands_by_category = {k: [i.get('command') for i in v] for k, v in sorted_commands.items()}

所有这一切都是针对每个类别项目,使用列表推导获取字典列表并仅保留命令名称。

完整示例:

from itertools import groupby
from typing import Callable, Iterable

def group_by(iterable: Iterable, key: Callable) -> dict:
    return {r[0]: list(r[1]) for r in groupby(sorted(iterable, key=key), key)}

ls = [{"category": "Information", "command": "info"},
      {"category": "Owneronly", "command": "ban"},
      {"category": "Owneronly", "command": "kick"},
]

expected = {
    "Information": ["info"],
    "Owneronly": ["ban", "kick"],
}

sorted_commands = group_by(ls, lambda x: x.get("category"))
commands_by_category = {k: [i.get('command') for i in v] for k, v in sorted_commands.items()}

commands_by_category == expected  # True

这种方法虽然更密集,但功能更强大,并且利用了 Python 核心库。结果,我敢打赌它会更快。


推荐阅读