Преобразование между двумя наборами констант

У меня есть два перечисления NAME и ALIAS, которые гарантированно содержат одинаковое количество констант, и мне нужен способ преобразования каждой константы из NAME в соответствующую ей из ALIAS и наоборот. Например:

def name_to_alias(name):
    if name == Name.PAUL:
        return Alias.STARCHILD
    elif name == Name.GENE:
        return Alias.DEMON
    ...

def alias_to_name(alias):
    if alias == Alias.STARCHILD:
        return Name.PAUL
    elif alias == Alias.DEMON:
        return Name.GENE
    ...

Я не хочу поддерживать две подобные функции (или диктовки). В идеале я хотел бы иметь сопоставления перечислений в одной структуре данных, к которой я мог бы получить доступ из обеих функций преобразования.

Я думаю о чем-то вроде:

mappings = {
    Name.PAUL: Alias.STARCHILD
    Name.GENE: Alias.DEMON
    ...
}

Это будет работать для преобразования из Name в Alias, но в обратном случае могут возникнуть проблемы (что произойдет, если я сделаю ошибку копирования и вставки и в итоге получу два dict-ключа с одинаковым значением?). Есть ли простой и безопасный способ добиться этого?

«Что произойдет, если у меня случайно окажется два ключа dict с одинаковым значением?» Не делайте этого, дикты так не работают. При необходимости вы можете создать список значений с одним ключом, но как бы вы выбрали один из разных вариантов?

Mark Ransom 01.07.2024 17:44

Похоже, вам следует избавиться от перечислений

klutt 01.07.2024 17:46

@MarkRansom «Дикты так не работают», конечно, работают; d = {"a": 1, "b": 1} — это совершенно правильный Python. В этом случае было бы ошибкой иметь такие повторяющиеся значения, поэтому я сказал «случайно».

Martin 01.07.2024 17:48

@klutt, к сожалению, это не так просто, поскольку они глубоко встроены в две разные части системы, которые я пытаюсь заставить общаться друг с другом.

Martin 01.07.2024 17:49

@Martin Это удивительно, учитывая, что вы только что гарантировали, что два типа перечислений имеют одинаковое количество членов - как вы скомпилировали Alias с конфликтующими именами членов? Возможно, отображение не так симметрично, как вы изначально предполагали?

Mathias R. Jessen 01.07.2024 17:51

@MathiasR.Jessen Я имел в виду, что могу допустить ошибку копирования и вставки при добавлении новых записей в словарь. Перечисление, имеющее одинаковое количество членов, не имеет к этому никакого отношения. Я отредактировал вопрос, чтобы прояснить это.

Martin 01.07.2024 17:56

Ваш редактор (или, в конечном итоге, среда выполнения Python, выполняющая ваш код) сообщит вам, что произошло столкновение, и вы сможете вернуться и исправить свою ошибку. Боюсь, я не понимаю, какое отношение небрежное копирование имеет к вашему вопросу о сопоставлении значений перечисления. Можете ли вы рассказать нам больше об отношениях между Name и Alias? Это 1 к 1 или многие к 1?

Mathias R. Jessen 01.07.2024 18:01

Я предполагаю, что ваша функция get_name из псевдонима должна возвращать все совпадающие имена, например def alias_to_name(alias): return [name for name, a in mappings.items() if a == alias]

Pepe N O 01.07.2024 18:04

@PepeNO, вот в чем проблема: в идеальном мире таких значений не было бы больше одного. Думаю, в этом случае я мог бы просто добавить проверку и ошибку, но я надеялся на более «элегантное» решение.

Martin 01.07.2024 18:09

@MathiasR.Jessen, счет 1:1. Я не понимаю, как среда выполнения автоматически обнаружит эту проблему; как я уже сказал, d = {"a": 1, "b": 1} — это совершенно правильный Python. Если бы я сделал то, что рекомендовал @PepeNO, мне все равно пришлось бы добавить ручную проверку, чтобы убедиться, что найдено только одно значение.

Martin 01.07.2024 18:15

@Мартин, я думал, ты говоришь о создании обратного словаря, который позволит искать ключи на основе их значений.

Mark Ransom 01.07.2024 18:44

@MatBailie да, это может сработать.

Martin 02.07.2024 09:10
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
12
64
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Учитывая, что в сопоставлениях более одного имени может иметь один и тот же псевдоним, безопасная функция должна вызывать ошибку, например

mappings = {
    Name.PAUL: Alias.STARCHILD,
    Name.GENE: Alias.DEMON,
    Name.PETER: Alias.CATMAN,
    Name.ALICE: Alias.DEMON
}

def alias_to_name(alias):
#check if the alias is more than once in the mappings and raise an error
    if list(mappings.values()).count(alias) > 1:
        raise ValueError('Alias is not unique', alias, [name for name, a in mappings.items() if a == alias])
    else:
        return [name for name, a in mappings.items() if a == alias]

Это выведет

('Alias is not unique', <Alias.DEMON: 2>, [<Name.GENE: 2>, <Name.ALICE: 4>])

Да, именно об этом я и думал. Но я ожидал, что будет существовать более «элегантное» решение, например. полностью использовать другую структуру данных и т. д.

Martin 01.07.2024 18:26

Это линейный поиск. Это может быть хорошо для коротких списков, но очень дорого для больших. Мало того, проверка нескольких псевдонимов удваивает объем необходимой работы.

Mark Ransom 01.07.2024 18:47

Другие вопросы по теме

Попытка получить dict[k] из dict в списке dicts для k в списке или строке
Создание столбца на основе значений столбца и словарей с использованием векторизации в pandas
Есть ли какая-либо польза от использования словарного понимания, если возможен эквивалентный dict(zip(a, b))?
Как сохранить все ключи/значения словаря в одной строке для хранения?
Преобразование плоского словаря с кортежами в качестве ключей во вложенный словарь
Как я могу использовать словарь для переключения между классами в соответствии с целочисленным значением?
Как правильно отсортировать вложенный словарь по ключам в Python3, где мы берем номера счетов из строк ключей
Как динамически выполнять list.map внутри виджета (Dart/Flutter)
Как объединить сложные словари в список сложных слов, где ключ появляется несколько раз
Как я могу получить все файлы, присутствующие в каталоге, с их хэшами в виде словаря на С#?