Подтвердить что ты не робот

Несколько ключей на стоимость

Можно ли назначить несколько ключей на одно значение в словаре Python. Одним из возможных решений является назначение значения для каждого ключа:

dict = {'k1':'v1', 'k2':'v1', 'k3':'v1', 'k4':'v2'}

но это не эффективно с точки зрения памяти, так как мой файл данных составляет > 2 ГБ. В противном случае вы можете сделать словарь словарных клавиш:

key_dic = {'k1':'k1', 'k2':'k1', 'k3':'k1', 'k4':'k4'}
dict = {'k1':'v1', 'k4':'v2'}
main_key = key_dict['k2']
value = dict[main_key]

Это тоже очень много времени и усилий, потому что я должен пройти через целый словарь/файл дважды. Есть ли еще одно простое и встроенное решение Python?

Примечание: мои значения словаря не являются простыми строками (как в вопросе "v1", "v2" ) довольно сложными объектами (содержит другой словарь/список и т.д., и их невозможно рассолить)

Примечание: вопрос кажется похожим на Как я могу использовать как ключ, так и индекс для того же значения словаря?  Но я не ищу заказываемый/индексированный словарь, и я ищу другие эффективные решения (если они есть), кроме тех, которые упомянуты в этом вопросе.

4b9b3361

Ответ 1

Какой тип значения?

dict = {'k1':MyClass(1), 'k2':MyClass(1)}

предоставит объекты с двойными значениями, но

v1 = MyClass(1)
dict = {'k1':v1, 'k2':v1}

приводит к тому, что оба ключа ссылаются на один и тот же фактический объект.

В исходном вопросе ваши значения являются строками: даже если вы дважды объявляете одну и ту же строку, я думаю, что они будут интернированы на один и тот же объект в этом случае


NB. если вы не уверены, закончились ли вы с дубликатами, вы можете узнать вот так:

if dict['k1'] is dict['k2']:
    print("good: k1 and k2 refer to the same instance")
else:
    print("bad: k1 and k2 refer to different instances")

(is проверьте, спасибо J.F.Sebastian, заменив id())

Ответ 2

Проверьте это - это реализация именно того, что вы спрашиваете: multi_key_dict (ionary)

https://pypi.python.org/pypi/multi_key_dict (источники https://github.com/formiaczek/python_data_structures/tree/master/multi_key_dict)

(на платформах Unix это возможно как пакет, и вы можете попробовать установить его с помощью чего-то вроде:

sudo apt-get install python-multi-key-dict

для Debian или эквивалент для вашего распространения)

Вы можете использовать разные типы для ключей, но также и ключи того же типа. Также вы можете перебирать элементы с использованием выбранных вами типов ключей, например:

m = multi_key_dict()
m['aa', 12] = 12
m['bb', 1] = 'cc and 1'
m['cc', 13] = 'something else'

print m['aa']   # will print '12'
print m[12]     # will also print '12'

# but also:
for key, value in m.iteritems(int):
    print key, ':', value
# will print:1
# 1 : cc and 1
# 12 : 12
# 13 : something else

# and iterating by string keys:
for key, value in m.iteritems(str):
    print key, ':', value
# will print:
# aa : 12
# cc : something else
# bb : cc and 1

m[12] = 20 # now update the value
print m[12]   # will print '20' (updated value)
print m['aa']   # will also print '20' (it maps to the same element)

Нет ограничений на количество клавиш, поэтому код вроде:

m['a', 3, 5, 'bb', 33] = 'something' 

и любой из ключей можно использовать для обозначения созданного значения (либо для чтения/записи, либо для его удаления).

Изменить: Начиная с версии 2.0 он также должен работать с python3.

Ответ 3

Я удивлен, что никто не упомянул использование Tuples со словарями. Это прекрасно работает:

my_dictionary = {}
my_dictionary[('k1', 'k2', 'k3')] = 'v1'
my_dictionary[('k4')] = 'v2'

Ответ 4

Используя python 2.7/3, вы можете комбинировать пару кортежей, значение с пониманием словаря.

keys_values = ( (('k1','k2'), 0), (('k3','k4','k5'), 1) )

d = { key : value for keys, value in keys_values for key in keys }

Аналогичным образом можно также обновить словарь.

keys_values = ( (('k1',), int), (('k3','k4','k6'), int) )

d.update({ key : value for keys, value in keys_values for key in keys })

Я не думаю, что это действительно зависит от вашего вопроса, но в свете названия, я думаю, что это принадлежит здесь.

Ответ 5

Вы можете создать вспомогательный словарь объектов, которые уже были созданы из проанализированных данных. Ключом будут проанализированные данные, значение будет вашим сконструированным объектом - скажем, строковое значение должно быть преобразовано в некоторый конкретный объект. Таким образом, вы можете контролировать, когда создавать новый объект:

existing = {}   # auxiliary dictionary for making the duplicates shared
result = {}
for k, v in parsed_data_generator():
    obj = existing.setdefault(v, MyClass(v))  # could be made more efficient
    result[k] = obj

Затем все объекты дублирования словаря result будут представлены одним объектом класса MyClass. После создания результата вспомогательный словарь existing можно удалить.

Здесь dict.setdefault() может быть элегантным и кратким. Но вы должны позже проверить, не более ли более разговорчивое решение - см. Ниже. Причина в том, что MyClass(v) всегда создается (в приведенном выше примере), а затем выбрасывается, если существует его дубликат:

existing = {}   # auxiliary dictionary for making the duplicates shared
result = {}
for k, v in parsed_data_generator():
    if v in existing:
        obj = existing[v]
    else:
        obj = MyClass(v)
        existing[v] = obj

    result[k] = obj

Этот метод может использоваться также, когда v не преобразуется ни в какие специальные. Например, если v является строкой, то и ключ, и значение во вспомогательном словаре будут иметь одинаковое значение. Однако наличие словаря гарантирует, что объект будет разделяться (что не всегда обеспечивается Python).

Ответ 6

Мне удалось достичь аналогичной функциональности, используя pandas MultiIndex, хотя в моем случае значения являются скалярами:

>>> import numpy
>>> import pandas
>>> keys = [numpy.array(['a', 'b', 'c']), numpy.array([1, 2, 3])]
>>> df = pandas.DataFrame(['val1', 'val2', 'val3'], index=keys)
>>> df.index.names = ['str', 'int']
>>> df.xs('b', axis=0, level='str')
        0
int      
2    val2

>>> df.xs(3, axis=0, level='int')
        0
str      
c    val3

Ответ 7

Самый простой способ сделать это - построить словарь, используя метод dict.fromkeys(). Он принимает последовательность ключей и значение в качестве входов, а затем присваивает значение каждому ключу.
Ваш код будет выглядеть следующим образом:

dict = dict.fromkeys(['k1', 'k2', 'k3'], 'v1')
dict.update(dict.fromkeys(['k4'], 'v2'))

И результат:

print(dict)
{'k1': 'v1', 'k2': 'v1', 'k3': 'v1', 'k4': 'v2'}