多对一映射(创建等价类)

19 投票
4 回答
16125 浏览
提问于 2025-04-15 17:07

我有一个项目,需要把一个数据库转换成另一个数据库。其中一个原始数据库的列是用来定义每一行的类别。这个列需要映射到新数据库中的一个新类别。

举个例子,假设原始的类别有:parrot, spam, cheese_shop, Cleese, Gilliam, Palin

这些类别对我来说有点多,我想把这些行归类为sketch, actor,也就是说,把所有的草图和所有的演员定义为两个相等的类别。

>>> monty={'parrot':'sketch', 'spam':'sketch', 'cheese_shop':'sketch', 
'Cleese':'actor', 'Gilliam':'actor', 'Palin':'actor'}
>>> monty
{'Gilliam': 'actor', 'Cleese': 'actor', 'parrot': 'sketch', 'spam': 'sketch', 
'Palin': 'actor', 'cheese_shop': 'sketch'}

这样做有点麻烦,我更希望能有类似这样的结构:

monty={ ('parrot','spam','cheese_shop'): 'sketch', 
        ('Cleese', 'Gilliam', 'Palin') : 'actors'}

不过,这样做的话,整个元组就会被当作一个键:

>>> monty['parrot']

Traceback (most recent call last):
  File "<pyshell#29>", line 1, in <module>
    monty['parrot']
KeyError: 'parrot'

有没有什么好的方法可以在Python中创建一个优雅的多对一字典?

4 个回答

3
>>> monty={ ('parrot','spam','cheese_shop'): 'sketch', 
        ('Cleese', 'Gilliam', 'Palin') : 'actors'}

>>> item=lambda x:[z for y,z in monty.items() if x in y][0]
>>>
>>> item("parrot")
'sketch'
>>> item("Cleese")
'actors'

不过我得告诉你,这种字典的速度会比普通的一对一字典慢。

5

你可以重写字典的索引器,但也许下面这个更简单的解决方案会更好:

>>> assoc_list = ( (('parrot','spam','cheese_shop'), 'sketch'), (('Cleese', 'Gilliam', 'Palin'), 'actors') )
>>> equiv_dict = dict()
>>> for keys, value in assoc_list:
    for key in keys:
        equiv_dict[key] = value


>>> equiv_dict['parrot']
'sketch'
>>> equiv_dict['spam']
'sketch'

(也许可以把嵌套的for循环压缩成一个很酷的单行代码,但这个方法有效且易于阅读。)

18

看起来你有两个问题。首先,你想知道怎么把你的映射关系写到新的文件 new_mapping.py 里。其次,你想了解在重新映射的过程中,这个映射是怎么运作的。这两种表示方式不一定要相同。

先从你喜欢的映射开始:

monty = { 
    ('parrot','spam','cheese_shop'): 'sketch', 
    ('Cleese', 'Gilliam', 'Palin') : 'actors',
}

然后把它转换成你需要的映射:

working_monty = {}
for k, v in monty.items():
    for key in k:
        working_monty[key] = v

这样就得到了:

{'Gilliam': 'actors', 'Cleese': 'actors', 'parrot': 'sketch', 'spam': 'sketch', 'Palin': 'actors', 'cheese_shop': 'sketch'}

接着用 working_monty 来完成这个工作。

撰写回答