"Один" для вложенных операторов "if"

У меня есть проблема, которая может быть упрощена:

parameters: a, b

if (a > 5)
{
    Print("Very well, a > 5");

    if (b > 7)
        Print("Even better, b > 7");
    else
    {
        Print("I don't like your variables");
    }
}
else
{
    Print("I don't like your variables");
}

Я хотел бы использовать только один else вместо двух, поскольку они являются одним и тем же кодом. Я думал о создании дополнительного метода, который возвращает объединенный true `false`, но это серьезный перебор.

Другим вариантом будет goto, но это сделает код менее читаемым и небезопасным.

Каким образом это можно сделать, избегая проверки одного и того же состояния много раз и делая его максимально читаемым?

Ответы

Ответ 1

Логическая логика 101:

public void test(int a, int b, int c) {
    boolean good = true;
    if (good = good && a > 5) {
        System.out.println("Very well, a > 5");
    }
    if (good = good && b > 7) {
        System.out.println("Even better, b > 7");
    }
    if (good = good && c > 13) {
        System.out.println("Even better, c > 13");
    }
    // Have as many conditions as you need, and then
    if (!good) {
        System.out.println("I don't like your variables");
    }
}

В качестве альтернативы - если вы хотите загрузить проверки -

enum Tests {
    A_gt_5 {
        @Override
        boolean test(int a, int b, int c) {
            return a > 5;
        }
    },
    B_gt_7 {
        @Override
        boolean test(int a, int b, int c) {
            return b > 7;
        }
    },
    C_gt_13 {
        @Override
        boolean test(int a, int b, int c) {
            return c > 13;
        }
    };

    abstract boolean test (int a, int b, int c);
}

public void test(int a, int b, int c) {
    boolean good = true;
    for ( Tests t : Tests.values() ) {
        good = good && t.test(a, b, c);
        if (!good) {
            break;
        }
    }
    if (!good) {
        System.out.println("I don't like your variables");
    }
}

Ответ 2

void doILikeYourVariables(int a, int b) {
  if (a > 5) {
    Print("Very well, a > 5");
    if (b > 7) {
      Print("Even better, b > 7");
      return;
    }
  }
  Print("I don't like your variables");
}

Ответ 3

if (a > 5)
{
    Print("Very well, a > 5");
}
if(a > 5 && b >7)
{
    Print("Even better, b > 7");
}
else
{
    Print("I don't like your variables");
}

или

bool isEvenBetter = false;
if (a > 5)
{
    Print("Very well, a > 5");
    isEvenBetter = b > 7;
}
if(isEvenBetter)
{
    Print("Even better, b > 7");
}
else
{
    Print("I don't like your variables");
}

Ответ 4

На самом деле для вашего случая есть только один экземпляр, где вы "любите" переменные, а именно a>5 and b>7. В этом случае вам нужно установить флаг во внутреннем if. Вот так:

parameters: a, b

boolean good = false;
if (a > 5){
    Print("Very well, a > 5");
    if (b > 7){
        Print("Even better, b > 7");
        good = true;
    }
}
if(!good){
    Print("I don't like your variables");
}

Это только дополнительная строка (и одна переменная) при удалении нескольких else (на самом деле даже нет else!)


Боковое примечание

Я бы сказал, что с использованием goto (или что-нибудь похожее на то, что поддерживается) в этом случае допустимо.

Я согласен с тем, что "безусловное использование goto" плохое, поскольку оно смущает поток программы, но в некоторых ситуациях лучше всего использовать goto, как и тот случай, который вы описываете.

Смотрите этот вопрос: GOTO по-прежнему считается вредным?

Собственно, если вы думаете об этом, повышение (возможно, обычное) исключение равно так же, как и goto, потому что он заставит поток программы перейти к определенной точке (что означает catch или except).

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

Ограниченный goto (например, обработка исключений в Java, которая может использовать только "goto" для строки "catch" ), хороша.

Я не говорю, что вы должны использовать goto, но я говорю о том, что вы говорите "goto is bad" и в то же время вносите свой вклад в пул ответов.

Ответ 5

Вы можете изменить состояние:

bool good = a > 5;
if(good)
{
    Print("Very well, a > 5");
    good = b > 7;
    if(good) {
        Print("Even better, b > 7");
    }
}
if( ! good) {
    Print("I don't like your variables");
}

Ответ 6

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

parameters: a, b

do {
  if (a > 5)
  {
    Print("Very well, a > 5");

    if (b > 7)
    {
        Print("Even better, b > 7");
        break;
    }
  }

  Print("I don't like your variables");
} while (false);

РЕДАКТИРОВАТЬ - при повторном использовании языка

Ряд людей возражал против этого специализированного использования, а для решения конкретной проблемы. Основное возражение, по-видимому, состоит в том, что он представляет собой цикл, но на самом деле не является циклом, поэтому эта конструкция попадает в своего рода сверхъестественную долину использование цикла. Другими словами, "это просто неестественно".

И я согласен с тем, что это необычное использование, и на самом деле должны быть комментарии, чтобы определить, что это фильтр, используя команду do while, чтобы создать блок, позволяющий использовать инструкции break всякий раз, когда достигается конечная точка ветвления дерева решений. Это действительно то, что это - жестко закодированное дерево дерево решений с прямым движением без возврата, состоящее из ряда решений. В любой момент процесса принятия решения мы можем вырваться с решением или пройти с решением по умолчанию, в котором не указано никакого решения.

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

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

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

Просматривая Интернет, вы можете найти немало статей, в которых кто-то использует язык программирования, отличный от его оригинального дизайна, например, эту статью на используя С++ в стиле функционального программирования или в этой онлайн-книге с использованием объектно-ориентированных практик с языком программирования C..

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

Это не сложный код, который можно найти в качестве записи в Obfuscated C Programming contest. Это довольно просто.

Изменить: лучше, чем goto?

Один вопрос об этом необычном использовании do while: "Почему бы просто не использовать goto?" Чтение Dijkstra essay of Go To Statement считается вредным, а также это обсуждение блога на эссе и инструкции goto, мы можем видеть, что есть несколько хороших характеристик использования цикла с операторами break, которые не являются характеристиками goto и связанной с ним метки.

Основная характеристика, особенно в этом примере, - это односторонний поток, в котором есть определенное начало и определенный конец. Существует опасность непреднамеренного изменения потока программы путем перемещения метки goto. Нет никакой опасности в другом месте функции, использующей метку goto как подходящее место для перехода к созданию зависимости, изначально не предназначенной. Читая код, каждый программист знает, что там, где есть разрыв, вы покидаете цикл, и после выхода из цикла вы переходите к исходной строке после закрытия цикла. В результате у вас есть хороший чистый кусок знаний, то, что можно обозначить как "выяснить текст для печати"

Ответ 7

Просто для удовольствия!

class VariableLiker {
  private:
    bool isGood_;
  public:
    VariableLiker() : isGood_(false) {}
    void checkA(int a) {
      if (a > 5) {
        Print("Very well, a > 5");
        isGood_ = true;
      }
    }
    void checkB(int b){
      if (isGood_ && b > 7)
        Print("Even better, b > 7");
      else
        Print("I don't like your variables");
    }
};

//...

VariableLiker variableLiker;
variableLiker.checkA(a);
variableLiker.checkB(b);

Ответ 8

Глядя на все ответы, я бы написал это так и сохранил оба elses. Нет смысла его усложнять.

parameters: a, b

if (a > 5)
{
    Print("Very well, a > 5");

    if (b > 7)
        Print("Even better, b > 7");
    else
        DontLikeIt();
}
else
{
    DontLikeIt();
}

И у вас есть метод DontLikeIt(), который печатает ответ, который вы хотите.

Ответ 9

Интересным аспектом вашего кода является то, что даже если ему нравится a, он "не любит ваши переменные", если b тогда недостаточно.

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

if (a > 5)
    Print("Very well, a > 5");
else
    b = 0;

if (b > 7)
    Print("Even better, b > 7");
else
    Print("I don't like your variables");

Если вам нужно сохранить значение b, тогда вы можете использовать дополнительную переменную.

var evenBetter = (b > 7);
if (a > 5)
    Print("Very well, a > 5");
else
    evenBetter = false;

if (evenBetter)
    Print("Even better, b > 7");
else
    Print("I don't like your variables");

Здесь версия, которая не требует предварительного расчета до тех пор, пока это не понадобится. Это лучше, если тест стоит дорого или может вызвать побочные эффекты. Это также избавляет от другого, если это действительно важно.; -)

var evenBetter = false;
if (a > 5)
{
    Print("Very well, a > 5");
    evenBetter = (b > 7);
}

if (evenBetter)
    Print("Even better, b > 7");
else
    Print("I don't like your variables");

Недостатком этого метода "расщепления" является то, что небрежный читатель может предположить, что второй оператор if не имеет ничего общего с a и, таким образом, не учитывает необычный случай, который "не нравится ваши переменные", возникает, когда хорошо, но b не является.

Ответ 10

Другой способ без перерыва или goto:

int c = (new[] { a > 5 ,a > 5 && b > 7 }).Count(x=>x);
if (c > 0)
{
    Print("Very well, a > 5 ");
}
if (c > 1)
{
    Print("Even better, b > 7");
}
else
{
    Print("I don't like your variables");
}

Ответ 11

Вы пробовали что-то вроде

string badResponse = "I don't like your variables";
string goodReponse = "Very well, a > 5";
string betterReponse = "Even better b > 7";

(a > 5) ? ((b>7) ? Print(betterReponse) : Print(goodReponse)) : Print(badResponse);

Ответ 12

если ((a < 5) || (b < 7)) print ( "Мне не нравятся ваши переменные" );

Инвертируйте логику и исправьте ее вместе. То, что вы делаете, - это "и"; поэтому сначала проверьте недействительные случаи и выполните дополнительные проверки ниже. Это также следует принципу DRY.

Ответ 13

 if (a > 5 && b > 7)
    {
        Print("Very well, a > 5");
        Print("Even better, b > 7");
    }
    else
    {
        if (a > 5)
        {
            Print("Very well, a > 5");
        }
        Print("I don't like your variables");

    }

Ответ 14

string msgFirstPart, msgSecondPart = "I don't like your variables";
if (a > 5) {
  msgFirstPart = "Very well, a > 5\n";
  if (b > 7)
    msgSecondPart = "Even better, b > 7";
}
Print(msgFirstPart + msgSecondPart);

Ответ 15

Ну, с 0 else и 0 if вы можете сделать, если вы используете С++:

switch ( ( a > 5 ) + ( ( b > 7 ) << 1 ) )
{
case 1:
    printf ( "Very well, a > 5" );
case 0:
case 2:
    printf ( "I don't like your variables" );
    break;
case 3:
    printf ( "Very well, a > 5" );
    printf ( "Even better, b > 7" );
    break;
}

В версии С# есть некоторые скрытые операторы if в виде тройных операторов: (используйте System.out.print для Java)

switch ( ( a > 5 ? 1 : 0 ) + ( b > 7 ? 2 : 0 ) )
{
case 1:
    Console.WriteLine ( "Very well, a > 5" );
    Console.WriteLine ( "I don't like your variables" );
    break;
case 0:
case 2:
    Console.WriteLine ( "I don't like your variables" );
    break;
case 3:
    Console.WriteLine ( "Very well, a > 5" );
    Console.WriteLine ( "Even better, b > 7" );
    break;
}

Ответ 16

используйте оператор ? :, иначе не потребуется. Так что тот же код будет удален, а также не будет другого метода или goto на картинке.

Примечание: Однако это не приведет к печати точного результата, если a > 5 и b < 7. Экстра "I don't like your variables" в этом случае не будет напечатана.

Пример:

string result = "I don't like your variables";

if (a > 5)
{
    result = (b > 7) ? "Even better, b > 7" : "Very well, a > 5";
}

Print(result);