Когда стоит использовать цикл над операторами if-else?

Предположим, что я ищу индекс some_array, где some_array равно target. Я знаю, что в python есть понимание списков и np.where(), оба из которых хорошо подходят для моих целей. Но также предположим, что я хочу сделать это с операторами if-elif-else или с циклом for. Реализации, если длина массива равна 3, будут выглядеть так:

if some_array[0]==target:
    return 0
elif some_array[1]==target:
    return 1
else:
    return 2 
for i in range(3):
    if some_array[i]==target:
        return i

Итак, когда лучше использовать цикл for вместо оператора if-elif-else? Меня больше всего интересуют его применения в python и C, т. е. switch-cases.

Мои подвопросы будут такими:

  • Переключаются ли компиляторы (или, в случае Python, numba или cython) с цикла for на switch-cases или наоборот, если им кажется, что другой подход быстрее?
  • Существует ли общепринятая практика кодирования, предполагающая максимальную длину операторов if-elif-else для лучшей читабельности?
  • Существует ли порог длины массива или количества итераций, при котором один из них работает лучше, чем другой?

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

Заранее спасибо!

«Повторное использование кода» всегда лучше, чем «копировать/вставить/адаптировать»… за исключением, пожалуй, тривиального случая двух операций.

Fe2O3 05.01.2023 22:27

Switch-cases обычно заменяется таблицей переходов, которая не всегда быстрее, чем набор условных переходов. Некоторые компиляторы адаптируют сгенерированный код на основе этого. Тем не менее, выбор зависит от входного набора данных, который компилятор не знает, поэтому, как правило, он не может создать эффективный код. Все это связано со сложными темами: предсказание переходов и декодирование инструкций. Из-за этого в некоторых случаях циклы могут работать быстрее, чем развернутый код. Вот почему удобочитаемость и профилирование имеют большое значение.

Jérôme Richard 06.01.2023 03:45

В большинстве случаев лучше позволить компиляторам сделать всю работу за вас, так как выбор также зависит от архитектуры. Хорошие компиляторы могут генерировать быстрый код SIMD, когда число итераций велико (хотя инструкции SIMD на самом деле могут быть медленнее в отношении варианта использования и входных данных). Обычно они не делают этого с набором условных выражений.

Jérôme Richard 06.01.2023 03:48

@JérômeRichard Большое спасибо! Это было так же полезно, как и ответы.

C.Koca 06.01.2023 05:12
Почему в 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 может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
2
4
96
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Производительность if не будет иметь значения. Цикл for был бы лучше, чем множество if для удобства чтения.

В этом конкретном случае просто используйте встроенную функцию, которая обычно работает быстрее.

return some_array.index(target)

Если возможно, что target нет в списке

try:
    return some_array.index(target)
except ValueError:
    return -1

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

C.Koca 05.01.2023 22:15

Единственный способ узнать конкретную производительность — протестировать свой код на нескольких машинах. Большинство реализаций Python не делают много оптимизаций.

Samathingamajig 05.01.2023 22:19

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

C.Koca 05.01.2023 22:21

Приблизительный ответ: «просто используйте цикл» ИМО. Мне нравится наблюдение в другом ответе, что компилятор может легко развернуть цикл в тех случаях, когда это выгодно, но он не может легко пойти в другом направлении. Это говорит о том, что с точки зрения программиста лучше всегда использовать цикл в коде, а не пытаться угадать компилятор (поскольку компилятор почти всегда будет лучше вас в оптимизации машинного кода).

Samwise 06.01.2023 00:38
Ответ принят как подходящий

Итак, когда лучше использовать цикл for вместо оператора if-elif-else?

Петля всегда понятнее, чем цепочка if-else if-else для этой конкретной цели. Это достаточная причина, чтобы предпочесть цикл, за исключением, возможно, очень маловероятного случая, когда вы проследите узкое место производительности в таком цикле и обнаружите, что его можно облегчить, заменив на if.

  • Компиляторы (или, в случае Python, numba или cython) переключаются с цикла for на switch-case или наоборот, если это похоже на другой подход быстрее?

Развертывание цикла — это стандартная оптимизация, которую выполняют многие компиляторы C, когда считают, что это даст улучшение. Короткая петля может быть полностью развёрнута, что и является той трансформацией, о которой вы спрашиваете.

Я не знаю компиляторов, выполняющих обратное преобразование.

  • Существует ли обычно ожидаемая хорошая практика кодирования, которая предлагает максимальную длину для операторов if-elif-else, чтобы обеспечить простоту? следуя коду?

Не как таковой.

Пишите понятный код и не повторяйтесь.

  • Существует ли порог длины массива или количества итераций, при котором один из них работает лучше, чем другой?

Не в частности. Производительность зависит от множества факторов и нескольких четких правил.

В общем, сначала заставить работать, потом, если нужно, сделать быстро.

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