У меня есть некоторый код, который имеет последовательность if
s, которая работает, но просто чувствую себя грязно. По сути, я хочу выбрать наибольшее из трех целых чисел и установить флаг статуса, чтобы сказать, какой из них был выбран. Мой текущий код выглядит так:
a = countAs();
b = countBs();
c = countCs();
if (a > b && a > c)
status = MOSTLY_A;
else if (b > a && b > c)
status = MOSTLY_B;
else if (c > a && c > b)
status = MOSTLY_C;
else
status = DONT_KNOW;
Этот шаблон встречается несколько раз, и с длинными именами переменных становится немного сложно визуально подтвердить, что каждый из if
них правильный. Я чувствую, что мог бы быть лучший и более ясный способ сделать это; кто-нибудь может предложить что-нибудь?
Есть несколько потенциальных дубликатов, но они не совсем соответствуют этому вопросу.
В предложенном дубликате: Подходы к проверке нескольких условий? Все предложенные решения кажутся такими же неуклюжими, как и исходный код, поэтому они не обеспечивают лучшего решения.
И этот пост Элегантные способы обработки, если (если еще) еще имеет дело только с уровнями вложенности и асимметрией, что не является проблемой здесь.
источник
Ответы:
Факторизовать логику, возвращаться рано
Как предлагается в комментариях, было бы достаточно просто обернуть свою логику в функцию и рано выйти из нее
return
, чтобы упростить многое. Кроме того, вы можете немного расширить функциональность, делегировав тесты другой функции. Более конкретно:Это короче, чем моя предыдущая попытка:
Выше приведено немного более многословно, но легко читается ИМХО и не пересчитывает сравнения несколько раз.
Визуальное подтверждение
В своем ответе вы говорите:
... также в своем вопросе вы говорите:
Возможно, я не понимаю, чего вы пытаетесь достичь: хотите ли вы копировать и вставлять шаблон везде, где вам это нужно? С помощью функции, подобной приведенной выше, вы фиксируете шаблон один раз и проверяете один раз все, что используют все сравнения
a
,b
и поc
мере необходимости. Тогда вам больше не нужно беспокоиться при вызове функции. Конечно, на практике ваша проблема немного сложнее, чем та, которую вы описали: если да, пожалуйста, добавьте некоторые детали, если это возможно.источник
MOSTLY_A
илиMOSTLY_C
в случаеa == c
иa > b
. Это исправлено. Спасибо.TL: DR; Ваш код уже правильный и "чистый".
Я вижу, как много людей колеблются вокруг ответа, но всем не хватает леса сквозь деревья. Давайте сделаем полную информатику и математический анализ, чтобы полностью понять этот вопрос.
Сначала отметим, что у нас есть 3 переменные, каждая из которых имеет 3 состояния: <, = или>. Общее количество перестановок составляет 3 ^ 3 = 27 состояний, которым я назначу уникальный номер, обозначаемый P #, для каждого состояния. Этот номер P # является факториальной системой счисления .
Перечисляя все перестановки, которые мы имеем:
При осмотре мы видим, что имеем:
Давайте напишем программу (см. Сноску) для перечисления всех этих перестановок со значениями для A, B и C. Стабильная сортировка по P #:
Если вам интересно, откуда я знаю, какие состояния P # невозможны, теперь вы знаете. :-)
Минимальное количество сравнений для определения порядка:
Log2 (27) = Log (27) / Log (2) = ~ 4,75 = 5 сравнений
т.е. coredump дал правильное 5 минимальное количество сравнений. Я бы отформатировал его код как:
Для вашей проблемы мы не заботимся о проверке на равенство, поэтому мы можем опустить 2 теста.
Неважно, насколько чист / плох код, если он получает неправильный ответ, так что это хороший признак того, что вы правильно обрабатываете все случаи!
Далее, что касается простоты, люди продолжают пытаться «улучшить» ответ, где они думают, что улучшение означает «оптимизацию» числа сравнений, но это не совсем то, что вы просите. Вы запутали всех, когда спросили: «Я чувствую, что может быть лучше», но не определили, что означает «лучше». Меньше сравнений? Меньше кода? Оптимальные сравнения?
Теперь, так как вы спрашиваете о читабельности кода (учитывая правильность), я бы сделал одно изменение в вашем коде для удобства чтения: выровняйте первый тест с остальными.
Лично я написал бы это следующим образом, но это может быть слишком необычным для ваших стандартов кодирования:
Сноска. Вот код C ++ для генерации перестановок:
Изменения: на основе обратной связи переместил TL: DR наверх, удалил несортированную таблицу, уточнил 27, очистил код, описал невозможные состояния.
источник
@msw сказал вам использовать массив вместо a, b, c, а @Basile сказал вам реорганизовать логику «max» в функцию. Объединение этих двух идей приводит к
затем предоставьте функцию, которая вычисляет максимальный индекс произвольного массива:
и называть это как
Кажется, что общее количество LOC увеличилось по сравнению с исходным, но теперь у вас есть основная логика в многократно используемой функции, и если вы можете многократно использовать эту функцию, она начинает окупаться. Более того, эта
FindStrictMaxIndex
функция больше не связана с вашими «бизнес-требованиями» (разделение интересов), поэтому риск, что вам придется изменить ее позже, намного ниже, чем в исходной версии (принцип открытого-закрытого доступа). Например, эту функцию не нужно будет изменять, даже если меняется число аргументов, или нужно использовать другие возвращаемые значения, кроме MOSTLY_ABC, или вы обрабатываете другие переменные, кроме a, b, c. Более того, использование массива вместо 3 различных значений a, b, c может упростить ваш код и в других местах.Конечно, если во всей вашей программе есть только одно или два места для вызова этой функции, и у вас нет других приложений для хранения значений в массиве, то я бы, вероятно, оставил исходный код как есть (или используйте улучшение Coredump).
источник
FindStrictMaxIndex()
не могут быть слишком чистыми, но с точки зрения вызывающего абонента вполне очевидно, что пытается быть достигнуто.int
типизированная функция. Но я согласен с вашим комментарием, если вы используете другой язык, такой как Python или Perl.FindStrictMaxIndex
функцию можно использовать повторно. Конечно, за один или два раза повторного использования это не окупится, но об этом я уже писал в своем ответе. Обратите внимание также на другие преимущества, которые я упомянул выше относительно будущих изменений.return result[FindStrictMaxIndex(val,3)];
в той точке кода, где были размещены исходные 8 строк . Другие части, особенноFindStrictMaxIndex
сама по себе, полностью отделены от «бизнес-логики», которая выводит их из фокуса меняющихся бизнес-требований.Вы, вероятно, должны использовать макрос или функцию,
MAX
дающую максимум два числа.Тогда вы просто хотите:
Вы могли бы определить
но будьте осторожны - особенно в отношении побочных эффектов - при использовании макросов (так как
MAX(i++,j--)
будет вести себя странно)Так что лучше определите функцию
и использовать его (или хотя бы
#define MAX(X,Y) max2ints((X),(Y))
....)Если вам нужно понять происхождение MAX, у вас может быть длинный макрос, такой
#define COMPUTE_MAX_WITH_CAUSE(Status,Result,X,Y,Z)
как longdo{
...}while(0)
макрос, возможноТогда вы можете вызвать
COMPUTE_MAX_WITH_CAUSE(status,res,a,b,c)
в нескольких местах. Это немного некрасиво. Я определил локальные переменныеx
,y
,z
снизить вредные побочные эффекты ....источник
Я больше думал об этом, так как моя проблема была в основном визуальным подтверждением того, что все сравнения использовали одни и те же переменные, я думаю, что это может быть полезным подходом:
То, что каждый макрос берет
a
,b
иc
в том же порядке легко подтвердить, и имя макроса избавляет меня от необходимости выяснять, что делают все сравнения и AND.источник