Python. Альтернатива оператору if для определения нужного значения
Всем привет. Пишу программу, которая на основе введенной строки формирует текст для электронного письма и отправляет письма на определенные Email-адреса.
Сложность заключается в том, что вводимая строка может быть разной, в одном случае, требуется отправить одно письмо одному получателю, а в другом может понадобится 2-3 письма для разных получателей с разным текстом.
Вводимая строка содержит список торговых центров, относящихся к ведению разных людей(получателей). И выглядит примерно следующим образом:
tc_list = "TC1, TC3, TC5, TC7, TC9, TC14"
Всего есть 3 группы торговых центров, у каждой из которых свой получатель, они записаны в словаре:
tc_dict = {
'Group-1': ('TC1', 'Постановка', 'прошу поставить ролик(и) в эфир', '[email protected]'),
'Group-2': [['TC2', 'TC3', 'TC4', 'TC5', 'TC6', 'TC7'], 'Постановка', 'прошу поставить ролик(и) в эфир','[email protected]'],
'Group-3': [['TC8', 'TC9', 'TC10', 'TC11', 'TC12', 'TC13', 'TC14'], 'Согласование', 'прошу согласовать ролик(и)','[email protected]']
}
Алгоритм должен удалять из словаря те торговые центры, которых нет во введенной строке, а также удалять из словаря группы, отсутствующие во введенной строке. Результатом исполнения функции является возвращение изменного словаря(на основе которого в последствии будут формироваться и отправляться письма).
Сейчас у меня это выглядит следующим образом:
# Сценарий №2 - в заявке есть ТЦ из Group-1, есть 1 или несколько ТЦ из Group-2, нет ни одного ТЦ Group-3.
if (
'TC1' in tc_list
and ('TC2' in tc_list or 'TC3' in tc_list or 'TC4' in tc_list or 'TC5' in tc_list or 'TC6' in tc_list or 'TC7' in tc_list)
and not ('TC8' in tc_list or 'TC9' in tc_list or 'TC10' in tc_list or 'TC11' in tc_list or 'TC12' in tc_list or 'TC13' in tc_list or 'TC14' in tc_list)
):
tc_str = ', '.join(TC for TC in tc_dict['Group-2'][0] if TC in tc_list)
tc_dict['Group-2'][0] = tc_str
del tc_dict['Group-3']
return tc_dict
Таких сценариев я насчитал 10:

Мой вопрос состоит в следующем. Я знаю, что могу просто при помощи оператора if задать действия на каждый из 10 сценариев. Но есть ли какой-нибудь иной способ решить данную задачу с меньшим количеством строк кода и не требующий вручную прописывать каждый сценарий?
Ответы (3 шт):
Сценариев всего 8 (у вас повторы), включая 3 "Нет" * - это трехбитные числа от 0 до 7 (000..111 binary).
Чтобы построить эти числа (номер сценария), нужно установить биты, соответствующие каждому из ТЦ, это можно сделать примерно так
mask = 0
for TC in TCList:
mask = mask or (1 << (TC.groupnumber-1))
При нескольких оговорках:
- Первая группа тоже будет списком, а не кортежем.
- Список ТЦ в первой группе тоже будет списком строк, а не строкой.
- Порядок следования ТЦ в группах не важен.
tc_list = "TC1, TC3, TC5, TC7, TC9, TC14"
tc_dict = {
'Group-1': [['TC1'], 'Постановка', 'прошу поставить ролик(и) в эфир', '[email protected]'],
'Group-2': [['TC2', 'TC3', 'TC4', 'TC5', 'TC6', 'TC7'], 'Постановка', 'прошу поставить ролик(и) в эфир','[email protected]'],
'Group-3': [['TC8', 'TC9', 'TC10', 'TC11', 'TC12', 'TC13', 'TC14'], 'Согласование', 'прошу согласовать ролик(и)','[email protected]']
}
out_dict = {key: [list(tc_fin)] + tc_dict[key][1:]
for key in tc_dict
if (tc_fin := set(tc_dict[key][0]) & set(tc_list.split(', ')))
}
print(out_dict)
Решение то, что называется в лоб.
- Берем каждую группу
- Делаем пересечение множества ТЦ в списке ТЦ со множеством ТЦ в группе
- Если пересечение не дало пустое множество добавляем эту группу в новый словарь, где в качестве списка ТЦ - пересечение множеств, а остальной список без изменений.
Примечание. Можно не конвертировать получившееся множество в список если последующему обработчику все равно какая там коллекция. [list(tc_fin)] -> [tc_fin]
На основе ответа @Alexey Trukhanov. Этот код чуть быстрее и более Python-Way по моему мнению.
tc_list = 'TC1, TC3, TC5, TC7, TC9, TC14'
tc_dict = {
'Group-1': [['TC1'], 'Постановка', 'прошу поставить ролик(и) в эфир', '[email protected]'],
'Group-2': [['TC2', 'TC3', 'TC4', 'TC5', 'TC6', 'TC7'], 'Постановка', 'прошу поставить ролик(и) в эфир','[email protected]'],
'Group-3': [['TC8', 'TC9', 'TC10', 'TC11', 'TC12', 'TC13', 'TC14'], 'Согласование', 'прошу согласовать ролик(и)','[email protected]']
}
tc_fin_in = set(tc_list.split(', '))
out_dict = {
key: [[*tc_fin_out], *tc_messages]
for key, [tc_fin, *tc_messages] in tc_dict.items()
if (tc_fin_out := set(tc_fin) & tc_fin_in)
}
print(out_dict)