在 Python 中反转字典

问题描述

这是一个反转字典的代码,但为了理解定义的函数 invert_dict(dic) 中每个代码元素的作用,我遇到了一些麻烦,如果有人将它分解给我并向我解释每个元素的任务。 谢谢。

{'meet': ['Lion'],1.2: ['Lion'],'yellow': ['Lion'],'milk': ['Cat'],0.3: ['Cat'],'white': ['Cat'],'Dog': ['dog'],1: ['dog'],'black': ['dog']}

输出

private int _disposed;
        private readonly string _fromEmail;
        private readonly SmtpClient _client;

public Emailer()
        {
            _disposed = 0;
            _fromEmail = "email";
            _client = new SmtpClient("domain-com.mail.protection.outlook.com",25)
            {
                EnableSsl = true,Credentials = new NetworkCredential(_fromEmail,"password")
            };
        }

public async Task SendEmailAsync(IList<string> to,string subject,string body)
        {
            using (MailMessage mail = new MailMessage())
            {
                mail.From = new MailAddress(_fromEmail);
                foreach (string toEmail in to)
                    mail.To.Add(toEmail);
                
                mail.Subject = subject;
                mail.Body = body;
                mail.IsBodyHtml = true;

                using (SmtpClient smtp = _client)
                {
                    smtp.Credentials = _client.Credentials;
                    smtp.EnableSsl = _client.EnableSsl;
                    await smtp.SendMailAsync(mail);
                }
            }
        }

解决方法

听起来像 defaultdict 的经典用法

animals = {'Lion':["meet",1.2,'yellow'],'Cat':["milk",0.3,'white'],'dog':["Dog",1,'black']}

from collections import defaultdict
def invert_dict(d):
    ret = defaultdict(list)
    d = [(v,k) for k,lst in d.items() for v in lst]
    for k,v in d.items():
        ret[k].append(v)
    return dict(ret)
,
{v: d.setdefault(v,[]).append(k) or d[v] for d in ({},) for k in dic for v in dic[k]}

让我们从右侧分解

for k in dic for v in dic[k]

使用值作为列表{ k: [v1,v2] }的字典并提取对应的键作为kv = [v1,v2]中的值列表

v: d.setdefault(v,)

for v in dic[k] 循环每个键的值,即 [v1,v2] 并使用 defaultdict 来标识结果字典中已经存在的值,如果存在,则附加来自原始字典到新生成的倒排字典。如果不是,则分配密钥。

对于一个样本{ k: [v1,v2,v3],z: [v1] },每次运行后,倒排字典的状态如下:

{}
{ v1 : [k] }
{ v1 : [k],v2 : [k] }
{ v1 : [k],v2 : [k],v3: [k] }
{ v1 : [k,z],v3: [k] }  # because v1 already exists,z is appended

这相当于:

from collections import defaultdict

def invert_dict_exploded(dic):
    d = defaultdict(list)
    for key in dic:
        for value in dic[key]:
            d[value].append(key)
    return dict(d)
,

我们需要按顺序从外到内:

  • 大括号和冒号符号
  • For 循环
  • 附加

大括号

大括号在 Python 中用于创建字典或集合。在这种情况下,它们用于创建字典,因为我们有 {key: value} 符号。在本次讨论中,我们称其为“返回的字典”。

For 循环

这些 for 循环相当于:

for d in ({},):
    for k in dic:
        for v in dic.values():
            ...

这是一种速记符号,可以方便地快速创建集合。当它没有被滥用时,它通常是非常可读的,比如在这种情况下,被滥用。

for d in ({},) 仅用于声明一个字典,该字典在迭代键和值时将位于那里(因为正如我们在上面看到的,它位于最外层循环中)。字典名为 d

附加

对于每个键/值对,我们通过使用冒号符号在返回的字典中创建一个新键,其中键实际上是输入值之一,然后我们做两件事:

  1. 在我们的 d 字典中添加一个项目,它始终是一个列表
  2. 将列表分配给给定的键

如果在字典中没有找到键 k.setdefault(v,[])[] 位将设置默认值 v,然后将返回该列表(新创建的空列表或找到的列表)在那个键上),然后 .append(k) 位使用它来将键作为值附加到该列表中。这会处理输入列表中具有相同值的项目的情况,将所有键收集在一起以获得该值,例如:

animals = {'Lion':["meet",'black'],'black']}

您可以在其中看到包含“黑色”项的多个列表并将输出以下内容:

{'meet': ['Lion'],1.2: ['Lion'],'yellow': ['Lion'],'milk': ['Cat'],0.3: ['Cat'],'black': ['Cat','dog'],'Dog': ['dog'],1: ['dog']}

注意“Cat”和“dog”键都被添加到结果中的“black”列表中。

最后,部分。 list.append() 函数始终返回 None,因为每个未显式返回的函数在 Python 中都会自动返回 None

or 运算符用于短路表达式。它被写成 A or B 并且读作“如果 A 的计算结果为真值,则表达式的计算结果为 A;如果 A 的计算结果为假值,则表达式的计算结果为 B”。 None 在布尔值中始终计算为 false,因此表达式 d.setdefault(v,[]).append(k) or d[v] 始终计算为 d[v],但仅在执行 setdefault()append() 之后。

v: d.setdefault(v,[]).append(k) or d[v] 因此可以读作:

在我们返回的字典中创建一个键v;如果 v 不是 d 的键,则设置 d[v] = [];将值 d[v] 附加到 k 并将 d[v] 设置为 v 的值。