Самый эффективный способ перекодировать эти несколько операторов if

Я знаю, что это нелепый пример, но я ищу более эффективный способ написать этот код. К каждому проекту добавляются разные значения в зависимости от того, в каком состоянии он находится. Это всего лишь небольшой фрагмент. Я потенциально мог бы захотеть расширить это для всех 50 состояний, что было бы большим количеством операторов if. Я мог бы выгрузить это в функцию, но тогда функция по-прежнему будет содержать все операторы if.

Projects = [['Project A', 'CT', '', ''], ['Project B', 'MA', '', ''], ['Project C', 'RI', '', '']]

for project in Projects:
    if project[1] == 'CT':
        project[2] = project[0] + project[1]
        project[3] = '222'
    elif project[1] == 'MA':
        project[2] = '123'
        project[3] = None
    elif project[1] == 'ME':
        project[2] = '12323'
        project[3] = '333'
    elif project[1] == 'RI':
        project[2] = 'asdf'
        project[3] = '3333'
print Projects

person user2242044    schedule 06.07.2015    source источник
comment
Вместо того, чтобы сваливать все это в функцию, разделите ее на несколько. проверьте это: stackoverflow.com/questions/ 60208/   -  person Will    schedule 06.07.2015
comment
Почему бы не сделать сопоставление {state: (project[2].impact, project[3].impact), ...}?   -  person jonrsharpe    schedule 06.07.2015
comment
@jonrsharpe. Я не очень хорошо разбираюсь в картографии. Не могли бы вы рассказать об этом подробнее?   -  person user2242044    schedule 06.07.2015
comment
Просто использование словарей решит эту проблему, если у вас нет большого количества значений на основе переменных (например, project[0] + project[1])   -  person SuperBiasedMan    schedule 06.07.2015
comment
См., например. docs.python.org/2/tutorial/datastructures.html#dictionaries   -  person jonrsharpe    schedule 06.07.2015


Ответы (2)


Использование сопоставления словаря:

for project in Projects:
    project[2:4] = {
        'CT': [project[0]+project[1], '222'],
        'MA': ['123', None],
        'ME': ['12323', '333'],
        'RI': ['asdf', '3333']
    }[project[1]]

удаляет все if/else и просто имеет дело с реальными данными :)

Как было предложено jonrsharpe, может быть более эффективной задержка оценки значений словаря с помощью lambdas (за счет написания большего количества ):

for project in Projects:
    project[2:4] = {
        'CT': lambda: [project[0]+project[1], '222'],
        'MA': lambda: ['123', None],
        'ME': lambda: ['12323', '333'],
        'RI': lambda: ['asdf', '3333']
    }[project[1]]()


Изменить: объяснение для user2242044:

рассмотрите функцию:

def foo(x):
    print('*** foo(%s)' % x)
    return x

и посмотрите, что произойдет, когда вы это сделаете:

>>> {1: foo(1), 2: foo(2)}[1]
*** foo(1)
*** foo(2)
1

как видите, он вычисляет все значения в словаре, вызывая как foo(1), так и foo(2), а затем просто использует значение foo(1).

С lambdas:

>>> {1: lambda: foo(1), 2: lambda: foo(2)}[1]()
*** foo(1)
1

словарь возвращает функцию, и когда вы вызываете функцию, вычисляется значение, то есть вычисляется только значение foo(1)

person fferri    schedule 06.07.2015
comment
Недостатком этого является то, что он требует вычисления project[0]+project[1] даже для состояний, в которых это значение не будет использоваться. Задержка оценки (например, с помощью lambda) может быть более эффективной. - person jonrsharpe; 06.07.2015
comment
@jonrsharpe Опубликовать ответ? Было бы интересно посмотреть. - person George Stocker; 06.07.2015
comment
@jonrsharpe, если вычисления, выполняемые при построении словаря, тяжелые, это, безусловно, хорошая идея - person fferri; 06.07.2015
comment
@мескалинум. Меня всегда смущает lambda. Можете ли вы дать краткий обзор того, что делает второй блок кода по-другому. - person user2242044; 06.07.2015

Чтобы расширить мой комментарий и ответ мескалина, если некоторые воздействия на project[2] будут получены из других значений в project, вы можете поместить вызываемые объекты (например, с помощью lambdaexpressions) в словаре:

IMPACTS = {
    'CT': (lambda project: project[0] + project[1], '222'),
    'MA': ('123', None),
    ...,
}

Затем вы можете применить его как:

for project in Projects:
    two, three = IMPACTS[project[1]]
    try:
        project[2] = two(project)
    except TypeError:
        project[2] = two 
    project[3] = three

Если некоторые из значений project[3] будут различаться, вы можете аналогичным образом сделать их вызываемыми в словаре и применить ту же логику try/except (или if callable(...)) для фильтрации тех, которые нуждаются в вызове.

person jonrsharpe    schedule 06.07.2015