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 шт):

Автор решения: MBo

Сценариев всего 8 (у вас повторы), включая 3 "Нет" * - это трехбитные числа от 0 до 7 (000..111 binary).

Чтобы построить эти числа (номер сценария), нужно установить биты, соответствующие каждому из ТЦ, это можно сделать примерно так

mask = 0
for TC in TCList:
    mask = mask or (1 << (TC.groupnumber-1))
→ Ссылка
Автор решения: Alexey Trukhanov

При нескольких оговорках:

  1. Первая группа тоже будет списком, а не кортежем.
  2. Список ТЦ в первой группе тоже будет списком строк, а не строкой.
  3. Порядок следования ТЦ в группах не важен.
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)

Решение то, что называется в лоб.

  1. Берем каждую группу
  2. Делаем пересечение множества ТЦ в списке ТЦ со множеством ТЦ в группе
  3. Если пересечение не дало пустое множество добавляем эту группу в новый словарь, где в качестве списка ТЦ - пересечение множеств, а остальной список без изменений.

Примечание. Можно не конвертировать получившееся множество в список если последующему обработчику все равно какая там коллекция. [list(tc_fin)] -> [tc_fin]

→ Ссылка
Автор решения: Be3y4uu_K0T

На основе ответа @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)
→ Ссылка