Отображение «многие к одному» (создание классов эквивалентности)

У меня есть проект преобразования одной базы данных в другую. Один из исходных столбцов базы данных определяет категорию строки. Этот столбец должен быть сопоставлен с новой категорией в новой базе данных.

Например, предположим, что исходными категориями являются: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?


person Adam Matan    schedule 17.12.2009    source источник
comment
Посмотрите этот элегантный ответ на аналогичный вопрос.   -  person martineau    schedule 24.06.2012


Ответы (4)


Мне кажется, у вас есть две проблемы. Во-первых, как вы изначально выражаете свое сопоставление, то есть как вы вводите сопоставление в свой файл 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 для выполнения работы.

person Ned Batchelder    schedule 17.12.2009
comment
+1 Большое спасибо. Я предполагаю, что для этой работы нет родного типа Python; Как вы думаете, должен ли он быть? - person Adam Matan; 17.12.2009
comment
разве мы не можем иметь некоторую ссылку в качестве значения в паре (ключ, значение), а не хранить фактическую строку? Так как нет. ключей значительно больше, чем нет. значений, это сэкономит много места. Есть ли способ сделать это? - person ishan3243; 25.03.2014
comment
Старый вопрос, но что касается наблюдения @ishan3243, я почти уверен, что Python интернирует эти строки, поскольку они явно определены как константы. Кроме того, даже если значения считываются во время выполнения, из-за того, что этот код зацикливается и присваивает одну и ту же переменную каждому индексу, это должно вызывать интернирование строк. - person Spencer D; 30.12.2018

Вы можете переопределить индексатор dict, но, возможно, будет лучше следующее более простое решение:

>>> 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 можно сжать до впечатляющей однострочной строки, но это работает и читабельно.)

person Vladimir Gritsenko    schedule 17.12.2009
comment
Не для слабонервных: equiv_dict = dict( sum([[(k, v) for k в ks] for (ks, v) in assoc_list], [])) - person Vladimir Gritsenko; 17.12.2009

>>> 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'

Но позвольте мне сказать вам, что это будет медленнее, чем обычный словарь один к одному.

person YOU    schedule 17.12.2009
comment
Медленно, но с другой стороны, не требует постоянной вторичной структуры данных. Можно ускорить в определенной степени, если не писать как лямбда и использовать понимание списка. - person martineau; 24.06.2012

Если вы хотите, чтобы несколько ключей указывали на одно и то же значение, т.е.

m_dictionary{('k1', 'k2', 'k3', 'k4'):1, ('k5', 'k6'):2} и получить к ним доступ как,

`print(m_dictionary['k1'])` ==> `1`.

Проверьте этот модуль Python с несколькими словарями multi_key_dict. Установите и импортируйте его. https://pypi.python.org/pypi/multi_key_dict

person psun    schedule 24.07.2016