Есть ли более эффективный способ написать несколько, если еще? [Дубликат]

На этот вопрос уже есть ответ:

Мне нужно чтобы сопоставить средний балл с оценкой буквы. Это означает

if (90 < avg && avg < 100) {
     return 'A';
} 

и т. Д. До 'F' с 5 операторами if-else.

Это много повторений, и диапазоны, к которым я соответствую, имеют одинаковую длину.

Есть ли более эффективный способ сделать это? Я не хочу повторять оператор if-else 5 раз.

-14
задан Trilarion 16 August 2019 в 10:30
поделиться

7 ответов

Можно найти этот подход подробным и сверхспроектированным. Да, это.

, Хотя, мне нравится путь, система классификации определяется.

class Test {
  public static void main(String[] args) {
    Map<String, Predicate<Integer>> gradingSystem = new HashMap<>();

    gradingSystem.put("A", mark -> mark >= 90 && mark <= 100);
    gradingSystem.put("B", mark -> mark >= 80 && mark < 90);

    translateScoreIntoGrade(86, gradingSystem); // B
    translateScoreIntoGrade(95, gradingSystem); // A
  }

  public static String translateScoreIntoGrade(int score, Map<String, Predicate<Integer>> gradingSystem) {
    return gradingSystem.entrySet().stream()
        .filter(gradePredicate -> gradePredicate.getValue().test(score))
        .findFirst()
        .map(Map.Entry::getKey)
        .orElseThrow(() -> new IllegalArgumentException("This grade isn't valid for this system!"));
  }
} 
5
ответ дан 10 September 2019 в 04:37
поделиться

Вы могли сделать это как этот пример:

public static String avgValuetoGrade(int value) {
        int index = value/10;
        int gradeIndex = Math.max(0, index - 4);
        return (char)('F'-gradeIndex );
    }

Первое деление Вы в среднем 10, Вы получаете номер 0-9 (целочисленное деление). Затем необходимо уменьшить номера 0-4 так или иначе до одного номера -4, дает Вам номера 0-5 и отображает 0-4 на 0. Тогда можно возвратить символ (благодаря @Carlos Heuberger).

3
ответ дан 10 September 2019 в 04:37
поделиться

Мне нравится использовать enum для этого вида проблемы.

Вы просто определяете свои диапазоны в перечислимых значениях и используете предикат.

import java.util.*;

public class MyClass {
    public static void main(String args[]) {
      System.out.println(Letter.getValue(13)); // B
      System.out.println(Letter.getValue(28)); // C
      System.out.println(Letter.getValue(43)); // empty
    }
}

enum Letter {

    A(1, 10), B(11, 20), C(21, 30);

    int min;
    int max;

    Letter (int min, int max) {
        this.min = min;
        this.max = max;
    }

    boolean inRange(int v) {
        return v >= min && v <= max;
    }

    static Optional<Letter> getValue(int i) {
        return Arrays.stream(values())
           .filter(v -> v.inRange(i))
           .findAny();
    }

}
6
ответ дан 10 September 2019 в 04:37
поделиться

Это было бы примером того же самого, записанного в функциональном стиле. Нет никакого повторения, но это является довольно подробным.

я не использовал бы его, если полосы не были различными размерами (где Вы можете целочисленное деление использования )

Map<Range<Integer>, Character> rangeToGrade = Map.of(
   Range.between(90, 100), 'A',
   Range.between(80, 90), 'B'
   //... the rest
);

int mark = 50;
char grade = rangeToGrade.entrySet().stream()
    .filter(e -> e.getKey().contains(mark))
    .map(Map.Entry::getValue)
    .findFirst()
    .orElse('?'); // or throw an exception

Map.of от Java 9. Range от, например, Apache палата общин

2
ответ дан 10 September 2019 в 04:37
поделиться

Только для показа (Java, не я), в версии 12 Java (предварительный просмотр включил), с помощью новых Выражений Переключателя:

String grade = switch(avg/10) {
    case 9,10 -> "A";
    case 8    -> "B";
    case 7    -> "C";
    case 6    -> "D";
    case 5    -> "E";
    default   -> "F";
};

или, очень гибкий, не будучи к ленивому:

String grade = switch(avg) {
    case 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100 -> "A";
    case 80, 81, 82, 83, 84, 85, 86, 87, 88, 89      -> "B";
    // you got the idea, I AM lazy
2
ответ дан 10 September 2019 в 04:37
поделиться

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

class StackOverflow
{
    public static void main(String args[])
    {
        char grades[]={'A','B','C','D','E','F'};
        convert(grades,95);
        convert(grades,90);
        convert(grades,110);
        convert(grades,123);
        convert(grades,150);
    }
    static void convert(char grades[],int marks)
    {
        if(marks<=90||marks>=150)
        {
            System.out.println("Invalid marks");
            return;
        }
        int val=marks/10-9;
        System.out.println(grades[val]);
    }
}

Примечание: Это предполагает, что 91-99 , А , 100-109 , B, 110-119 C и так далее. Если Вы хотите избежать, чтобы числа 100,110 и т.д. просто добавили правило || marks%10 == 0 в если оператор выше.

Hope это полезно:)

1
ответ дан 10 September 2019 в 04:37
поделиться

Примечание: Это сделано с помощью Java 8 и не имеет доступа к MapOf и не пользуется внешними библиотеками. Также не использовал Потоки для показывания других вариантов.

я сделал GradeBook класс, что, когда он инстанцируют, поле класса для Map заполнено ключами, используемыми для нахождения буквенной оценки. Можно тогда просто звонить .getGrade(int) от Вашего GradeBook, объект с также обработает случаи отрицательного входа и входа выше 100 с возвратом N. Иначе это возвратит корректный класс из Map.

Это - больше Объектно-ориентированного подхода вместо того, чтобы использовать static вызов метода:

public class GradeBook {

    private Map<Integer, Character> map;

    public GradeBook() {
        constructMap();
    }

    public char getGrade(int grade) {
        if (grade >= 0 && grade <= 100) {
            return map.get(Math.max(0, grade/10 - 4));
        }
        else {
            return 'N';
        }
    }

    public void constructMap() {
        //You can use MapOf to add all of them at once in Java9+
        map = new HashMap<>();
        map.put(0, 'F');
        map.put(1, 'E');
        map.put(2, 'D');
        map.put(3, 'C');
        map.put(4, 'B');
        map.put(5, 'A');
        map.put(6, 'A');
    }

    public static void main(String [] args) {

        GradeBook grades = new GradeBook();

        //Testing different values
        System.out.println(grades.getGrade(100));
        System.out.println(grades.getGrade(75));
        System.out.println(grades.getGrade(80));
        System.out.println(grades.getGrade(91));
        System.out.println(grades.getGrade(45));
        System.out.println(grades.getGrade(2));
        System.out.println(grades.getGrade(-1));
    }
}

Вывод:

A
C
B
A
F
F
N

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

1
ответ дан 10 September 2019 в 04:37
поделиться
Другие вопросы по тегам:

Похожие вопросы: