Подтвердить что ты не робот

Как уменьшить, если утверждения

Программа ниже функционирует по мере необходимости, но как уменьшить количество операторов if. Мне сказали, что если ваша функция содержит 2 или более оператора if, то вы делаете это неправильно. Какие-либо предложения? Я пробовал использовать инструкции switch, но это не сработало, потому что случай не может быть логическим.

for(int i = 1; i < 100; i++)
        {
        if(i % 10 == 3) 
        {
            System.out.println("Fizz" + "(" + i + ") 3%10");
        }

        if(i / 10 == 3)
        {
            System.out.println("Fizz" + "(" + i + ") 3/10");
        }


        if(i % 10 == 5) 
        {
            System.out.println("Buzz" + "(" + i + ") 5%10");
        }

        if(i / 10 == 5)
        {
            System.out.println("Fizz" + "(" + i + ") 5/10");
        }

        if(i / 10 == 7)
        {
            System.out.println("Fizz" + "(" + i + ") 7/10");
        }

        if(i%10 == 7)
        {
            System.out.println("Woof" + "(" + i + ") 7%10");
        }

        if(i % 3 == 0)
        {
            System.out.println("Fizz" + "(" + i + ") 3%==0");
        }

        if(i % 5 == 0)
        {
            System.out.println("Buzz" + "(" + i + ")5%==0");
        }

        if(i % 7 == 0)
        {
            System.out.println("Woof" + "(" + i + ")7%==0");    
        }

        if( (i % 7 !=0 ) && (i % 3 !=0 ) && (i % 5 !=0 )
                && (i % 10 !=3) && (i % 10 !=5 ) && (i%10 !=7 ) )
            System.out.println(i);
    }
4b9b3361

Ответ 1

Как создать метод для случаев:

 public void printIfMod(int value, int mod){
       if (value % 10 == mod)
          System.out.println(...);
 }

 public void printIfDiv(int value, int div){
       if (value / 10 == div)
          System.out.println(...);
 }

Тогда вместо связки if у вас есть набор вызовов для двух методов. Вы даже можете создать один метод, который вызывает оба вышеуказанных.

 public void printIf(int value, int div){
      printIfMod(value, div);
      printIfDiv(value, div);
 }

 for(int i = 1; i < 100; i++) {
      printIf(i, 3);
      printIf(i, 5);
      ....
 }

В приведенном выше коде количество ifs для меня меньше, чем количество повторного кода.

Ответ 2

Здесь небольшое улучшение с использованием двух операторов switch

switch(i / 10){
  case 3: // do something
    break;
  case 5: // do something else
    break;
  case 7: // do something else
    break;
}

switch(i % 10){
  case 3: // do something
    break;
  case 5: // do something else
    break;
  case 7: // do something else
    break;
}

К сожалению, вам понадобится один оператор switch для каждого делителя.

В качестве альтернативы вы можете включить ООП и создать абстракцию следующим образом:

public abstract class Processor {
    private final int divisor;
    private final int result;
    private final boolean useDiv; // if true, use /, else use %

    public Processor(int divisor, int result, boolean useDiv) {
        this.divisor = divisor;
        this.result = result;
        this.useDiv = useDiv;
    }
    public final void process(int i){
        if (
             (useDiv && i / divisor == result)
             || (!useDiv && i % divisor == result)
           ){
                doProcess(i);
            }
    }

    protected abstract void doProcess(int i);
}

Использование образца:

public static void main(String[] args) {
    List<Processor> processors = new ArrayList<>();
    processors.add(new Processor(10, 3, false) {
        @Override
        protected void doProcess(int i) {
            System.out.println("Fizz" + "(" + i + ") 3%10");
        }
    });
    // add more processors here
    for(int i = 1; i < 100; i++){
        for (Processor processor : processors) {
            processor.process(i);
        }
    }

}

Ответ 3

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

В вашем случае вам нужно проверить делимость, не имея возможности вывести одно из другого (т.е. если x делится на 7, это не значит, что оно также делится на 5 и т.д.). Все номера, которые вы используете, были специально выбраны просто так, поэтому вы попадаете в это.

Если, например, они сказали, проверьте делимость на 2, 3 и 6. Затем вы можете сначала проверить на 6, потому что тогда вы также можете указать делимость на 2 и 3. Или наоборот, проверьте на 2 и 3 и подразумевает, что он также делится на 6. Если все числа являются первичными, то вы просто не можете подразумевать. Таким образом, вам нужен код, чтобы проверить все индивидуально.

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

Мои два цента на этом...

Ответ 4

Здесь перечислены переходы. Они позволяют вам инкапсулировать функциональность в одном месте, а не распространять ее во время управления потоком.

public class Test {
  public enum FizzBuzz {
    Fizz {
      @Override
      String doIt(int n) {
        return (n % 10) == 3 ? "3%10"
                : (n / 10) == 3 ? "3/10"
                : (n / 10) == 5 ? "5/10"
                : (n / 10) == 7 ? "7/10"
                : (n % 3) == 0 ? "3%==0"
                : null;
      }

    },
    Buzz {
      @Override
      String doIt(int n) {
        return (n % 10) == 5 ? "5%10"
                : (n % 5) == 0 ? "5%==0"
                : (n / 10) == 3 ? "3/10"
                : (n / 10) == 5 ? "5/10"
                : (n / 10) == 7 ? "7/10"
                : null;
      }

    },
    Woof {
      @Override
      String doIt(int n) {
        return (n % 10) == 7 ? "7%10"
                : (n % 7) == 0 ? "7%==0"
                : null;
      }

    };

    // Returns a String if this one is appropriate for this n.
    abstract String doIt(int n);

  }

  public void test() {
    // Duplicates the posters output.
    for (int i = 1; i < 100; i++) {
      boolean doneIt = false;
      for (FizzBuzz fb : FizzBuzz.values()) {
        String s = fb.doIt(i);
        if (s != null) {
          System.out.println(fb + "(" + i + ") " + s);
          doneIt = true;
        }
      }
      if (!doneIt) {
        System.out.println(i);
      }
    }
    // Implements the game.
    for (int i = 1; i < 100; i++) {
      boolean doneIt = false;
      for (FizzBuzz fb : FizzBuzz.values()) {
        String s = fb.doIt(i);
        if (s != null) {
          if ( doneIt ) {
            System.out.print("-");
          }
          System.out.print(fb);
          doneIt = true;
        }
      }
      if (!doneIt) {
        System.out.print(i);
      }
      System.out.println();
    }
  }

  public static void main(String args[]) {
    try {
      new Test().test();
    } catch (Throwable t) {
      t.printStackTrace(System.err);
    }
  }

}

Ответ 5

Я начал писать ответ с кодом, но многие, многие избили меня. Единственное, что я бы сказал, о котором еще не упоминалось, это то, что эта конкретная метрика кода, о которой вы говорите, называется циклическая сложность и isn ' Это ужасно плохо.

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

О, и я бы заменил этот последний раздел:

if( (i % 7 !=0 ) && (i % 3 !=0 ) && (i % 5 !=0 )
            && (i % 10 !=3) && (i % 10 !=5 ) && (i%10 !=7 ) )
        System.out.println(i);

Используя логический флаг, такой как replaced = true, когда вызывается какой-либо из операторов замещения, приведенный выше оператор сворачивается в:

if (!replaced)
      System.out.println(i);

Ответ 6

Я бы сказал, что вы задаете неправильный вопрос. Вопрос, который, я думаю, вам следует задать, это: "Как я могу переписать этот код так, чтобы его легче понять человеком?"

Кредо "исключить, если утверждения" - общая идея для достижения этого, но в значительной степени зависит от контекста.

Печальный факт состоит в том, что многие из ответов обманывают этот очень простой алгоритм под видом "упрощения". Никогда не вводите объект для устранения нескольких утверждений if. В моей работе большинство кодов поддерживаются людьми, которые гораздо меньше понимают архитектуру, математику и код, чем оригинальный автор, поэтому вводят дополнительные конструкции и сложность для уменьшения кода от 50 физических линий до 30 физических линий, но делает его 4 раз труднее понять, это не победа.

Ответ 7

Ваш код повторяется. Рефакторинг с использованием петель для вашего:

for (int i = 1; i < 100; i++) {
    boolean found = false; // used to avoid the lengthy test for "nothing found"
    for (int j = 3; j <= 7; j += 2) { // loop 3, 5, 7
        if (i % 10 == j) {
            System.out.println("Fizz" + "(" + i + ") "+j+"%10");
            found = true;
        }

        if (i / 10 == j) {
            System.out.println("Fizz" + "(" + i + ") "+j+"/10");
            found = true;
        }

        if (i % j == 0) {
           System.out.println("Fizz" + "(" + i + ") "+j+"%==0");
           found = true;
        }
    }

    if (!found) {
        System.out.println(i);
    }
}

Ответ 8

Вы можете создать несколько переключателей:

switch (i/10) {
     case 3:
        System.out.println("Fizz" + "(" + i + ") 3/10");
        break;

    case 5:
        System.out.println("Fizz" + "(" + i + ") 5/10");
        break;

    case 7:
        System.out.println("Fizz" + "(" + i + ") 7/10");
        break;
    default:
        break;
}

switch (i%10) {
    case 3: 
        System.out.println("Fizz" + "(" + i + ") 3%10");
        break;
    case 5:
        System.out.println("Buzz" + "(" + i + ") 5%10");
        break;
    case 7:
        System.out.println("Woof" + "(" + i + ") 7%10");
        break;
    default:
        break;
}

В другом случае все еще нужно использовать оператор if.
Oracle добавил оператор switch, который использовал String в Java 7. Возможно, инструкция boolean switch появится позже.

Ответ 9

public class Test
{

    public static void main(String[] args)
    {

        final int THREE = 3;
        final int FIVE = 5;
        final int SEVEN=7;
        final int ZERO = 0;

        for (int i = 1; i < 100; i++)
        {
            modOperation("Fizz", i, THREE);

            divideOperation("Fizz", i, THREE);


            modOperation("Fizz", i, FIVE);

            divideOperation("Buzz", i, FIVE);



            modOperation("Woof", i, SEVEN);

            divideOperation("Fizz", i, SEVEN);


            modOperation("Fizz", i, ZERO);

            divideOperation("Fizz", i, ZERO);
        }

    }

    private static void divideOperation(String sound, int i, int j)
    {
        if (i / 10 == j) // you can add/expand one more parameter for 10 and later on 3 in this example.
        {
            System.out.println(sound + "(" + i + ") "+j+"/10");
        }
    }

    private static void modOperation(String sound, int i, int j)
    {
        if (i % 10 == j)
        {
            System.out.println(sound + "(" + i + ") "+j+"%10");
        }
    }
}

Итак, теперь у вас меньше if