Вопрос

Я выделил тест, чтобы определить, совпадают ли два элемента расписания из-за его нечитаемости.

Есть ли какое-нибудь приложение, помогающее упростить логическое утверждение?

Пример:(изначально это ошибочный пример, но раскрывает причины, по которым я это прошу)

if (x < y && y < z && x < z)  

может быть сведено к

if (x < y && y < z)

Мой код:

return (shift.Start <= shift2.Start && shift.End >= shift2.End) || (shift2.Start <= shift.Start && shift2.End >= shift.Start)

Мне бы хотелось сделать это проще, и я верю, что это возможно, но не знаю, как это сделать.

Поскольку это на самом деле не зависит от языка, было бы неплохо даже преобразовать его в другой сценарий для поиска возможностей, например, нет необходимости в том, чтобы он был на C #.

Это было полезно?

Решение

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

Например:

return (shift.Start <= shift2.Start && shift.End >= shift2.End) || (shift2.Start <= shift.StartTime && shift2.End >= shift.Start)

Для удобства чтения и сопровождения можно выполнить рефакторинг до:

bool bRetVal = false;
bRetVal = (    (   (shift.Start <= shift2.Start)
                && (shift.End >= shift2.End))
            || (   (shift2.Start <= shift.StartTime)
                && (shift2.End >= shift.Start)))
return bRetVal;

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

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

Устраните дублирующую логику, и вы убьете двух зайцев одним выстрелом.Вы получите DRY и получите имя функции (комментарий богача):

class Shift:
  def encompasses(other_shift)
    self.start <= other_shift.start && self.end >= other_shift.end

...

return shift1.encompasses(shift2) || shift2.encompasses(shift1)

Будьте очень, очень осторожны с такими изменениями.На первый взгляд они могут показаться простыми, а логическую логику (и законы ДеМоргана) не так уж сложно понять, но при рассмотрении отдельных случаев часто возникают потенциальные ошибки:

Например:if (x < y && y < z) можно упростить до if (x < z)

Это неправильно, если (x < z), y все еще может быть больше, чем z.Это состояние не пройдет ваши первоначальные тесты.

Хотя x < y && y < z подразумевает x < z (< транзитивно), обратное неверно, поэтому выражения не эквивалентны.Действительно, если y были определены как, скажем, Integer y = null, то первое может даже вызвать NPE в Java или UNKNOWN в SQL.

Есть ли какое-нибудь приложение, помогающее упростить логическое утверждение?

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

Существуют методы работы с булевой логикой.Когда я учился в колледже (BSEE), мы использовали Карты Карно.По сути, вы можете взять очень сложную произвольную таблицу истинности и определить правильное и оптимизированное логическое выражение.Мы использовали это, чтобы уменьшить количество логических элементов в схеме, что аналогично упрощению сложной схемы. if заявление.

Плюсы:

  • Вы можете относительно легко реализовать/оптимизировать очень сложную и произвольную таблицу истинности.

Минусы:

  • Получающаяся в результате логика обычно мало напоминала цель таблицы истинности.Как предположили другие, это «нечитабельно».
  • Изменение одной ячейки таблицы истинности часто приводило к полностью другое выражение.Простая настройка дизайна превращается в переписывание, поэтому его невозможно поддерживать.
  • Неоптимизированная логика стала намного дешевле, чем раньше, а затраты на проектирование остались прежними.

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

По моему мнению, немногие реальные проблемы достаточно сложны, чтобы действительно извлечь пользу из этого типа техники, но он существует.

Делая это, нужно быть очень осторожным...пример, который вы привели, например, просто не соответствует действительности...если x=1, y=2 и z=2, то x < y = true и x < z = true, но y < z = false.В подобных рассуждениях вам действительно нужно стремиться к читаемости кода в таких обстоятельствах и не беспокоиться о наиболее эффективном коде, который вы можете получить.

Иногда вы можете обернуть такие операторы, как

сдвиг.Начало <= сдвиг2.Начало && сдвиг.Конец >= сдвиг2.Конец

В логическую функцию, чтобы сделать ее более читабельной, например:

Функция ShiftWithinValidRange (ужасное имя, но суть вы поняли)
{
Возврат (shift.Start <= сдвиг2.Начало && сдвиг.Конец >= сдвиг2.Конец);
}

Предполагая, что Start и StartTime на самом деле должны быть одним и тем же полем, ваше условие сводится к

(a <= b && c >= d) || (b <= a && d >= c)

Мы можем превратить это в

(a <= b && d <= c) || (b <= a && c <= d)

но это все еще не похоже, что это сильно упрощает.

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

то естьв вашем примере, почему мы проверяем, x < z , когда мы действительно хотим знать x < y && y < z?

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

У меня нет для вас общего решения, но если я использую синтаксис Lisp, мне это кажется намного проще:

(and (< x y)
     (< y z)
     (< x z))

Затем обратите внимание на первые два предложения:

(and (< x y)
     (< y z))

можно объединить в:

(and (< x y z))

Таким образом, полное выражение теперь выглядит так:

(and (< x y z)
     (< x z))

Теперь очевидно, что второй излишен, поэтому все сводится к:

(and (< x y z))

или просто:

(< x y z)

который в синтаксисе C:

(x < y && y < z)

Я думаю, что ответ Уэйна Конрада правильный, но только в развлекательных целях, вот еще один способ сказать это (я думаю):

(long) shift.Start.CompareTo(shift2.Start) * (long) shift.End.CompareTo(shift2.End) <= 0

Это действительно быстрее?Я не знаю.Конечно, читать труднее.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top