Не получается вычислить среднеарифметическое между двумя объектами
Есть входные данные, массив объектов:
Школа № 32 математика - 80.0 русский язык - 80.0 инфрматика - 80.0 общий средний балл - 80.0
Школа № 71 математика - 91.0 русский язык - 89.0 инфрматика - 100.0 общий средний балл - 93.0
Школа № 1 математика - 15.0 русский язык - 60.0 инфрматика - 30.0 общий средний балл - 35.0
Школа № 32 математика - 100.0 русский язык - 100.0 инфрматика - 100.0 общий средний балл - 100.0
Школа № 1 математика - 75.0 русский язык - 99.0 инфрматика - 67.0 общий средний балл - 80.0
Школа № 17 математика - 78.0 русский язык - 87.0 инфрматика - 77.0 общий средний балл - 80.0
Школа № 89 математика - 66.0 русский язык - 54.0 инфрматика - 78.0 общий средний балл - 66.0
Необходимо, если номер школы совпадает, объеденить объект и в него записать среднеарифмитическое число. Выходные данные должны быть такие:
Школа № 71: математика - 91.0, русский язык - 89.0, инфрматика - 100.0, общий средний балл - 93.3
Школа № 32: математика - 90.0, русский язык - 90.0, инфрматика - 90.0, общий средний балл - 90.0
Школа № 17: математика - 78.0, русский язык - 87.0, инфрматика - 77.0, общий средний балл - 80.7
Школа № 89: математика - 66.0, русский язык - 54.0, инфрматика - 78.0, общий средний балл - 66.0
Школа № 1: математика - 45.0, русский язык - 79.5, инфрматика - 48.5, общий средний балл - 57.7
У меня вышло следующим образом:
import java.util.Comparator;
import java.util.Locale;
public class srSchool {
private int scNumber;
private double srMathS;
private double srRusS;
private double srInfoS;
private double srAllS;
public srSchool(int scNumber, double srMathS, double srRusS, double srInfoS, double srAllS) {
this.scNumber = scNumber;
this.srMathS = srMathS;
this.srRusS = srRusS;
this.srInfoS = srInfoS;
this.srAllS = srAllS;
}
public int getScNumber() {
return scNumber;
}
public srSchool setScNumber(int scNumber) {
this.scNumber = scNumber;
return this;
}
public double getSrMathS() {
return srMathS;
}
public srSchool setSrMathS(double srMathS) {
this.srMathS = srMathS;
return this;
}
public double getSrRusS() {
return srRusS;
}
public srSchool setSrRusS(double srRusS) {
this.srRusS = srRusS;
return this;
}
public double getSrInfoS() {
return srInfoS;
}
public srSchool setSrInfoS(double srInfoS) {
this.srInfoS = srInfoS;
return this;
}
public double getSrAllS() {
return srAllS;
}
public srSchool setSrAllS(double srAllS) {
this.srAllS = srAllS;
return this;
}
@Override
public String toString() {
return String.format(Locale.ENGLISH,"Школа № " + scNumber + " математика - " + "%.1f" + " русский язык - " + "%.1f" + " инфрматика - " + "%.1f" + " общий средний балл - " + "%.1f", getSrMathS(), getSrRusS(),getSrInfoS(),getSrAllS());
}
}
public class Main {
static Scanner in = new Scanner(System.in);
static int N = in.nextInt();
static CytiStat[] list = new CytiStat[N];
int count = 0;
srSchool[] school = new srSchool[N];
for (int i = 0; i < list.length; i++) {
school[i] = new srSchool(in.nextInt(), in.nextInt(), in.nextInt(), in.nextInt());
}
for (srSchool sr: school) {
System.out.println(sr);
ArrayList<Double> gradem = new ArrayList<>();
ArrayList<Double> grader = new ArrayList<>();
ArrayList<Double> gradei = new ArrayList<>();
TreeMap<Integer, Double> sch = new TreeMap<>();
srSchool[] school2 = new srSchool[N-count];
for (int i = 0; i < N - count; i++) {
if (school[i].getScNumber() == school[i + 1].getScNumber() && !isSum) {
double m = (school[i].getSrMathS() + school[i + 1].getSrMathS()) / count;
double r = (school[i].getSrRusS() + school[i + 1].getSrRusS()) / count;
double info = (school[i].getSrInfoS() + school[i + 1].getSrInfoS()) / count;
gradem.add(m);
grader.add(r);
gradei.add(info);
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
if (school[i].getScNumber() == school[j].getScNumber()) {
school2[i] = new srSchool(list[i].getnSchool(), gradem.get(i), grader.get(i), gradei.get(i), (gradem.get(i) + grader.get(i) + gradei.get(i)) / 3);
isSum=true;
}
}
Выдает ошибку:
Exception in thread "main" java.lang.IndexOutOfBoundsException: Index 2 out of bounds for length 2
at java.base/jdk.internal.util.Preconditions.outOfBounds(Preconditions.java:64)
at java.base/jdk.internal.util.Preconditions.outOfBoundsCheckIndex(Preconditions.java:70)
at java.base/jdk.internal.util.Preconditions.checkIndex(Preconditions.java:248)
at java.base/java.util.Objects.checkIndex(Objects.java:372)
at java.base/java.util.ArrayList.get(ArrayList.java:458)
at OOP.Exams.Main.main(Main.java:76)
Подскажите что не так, и как сдлать чтобы работало?
Ответы (2 шт):
У Вас проблемы в алгоритме. Попробуйте решить её немного по другому.
Добавьте поле количество статистик по школе. по умолчанию = 1, увеличиваете на повторении школы. StatsCount
Сделайте среднее арифметическое вычислимым полем. (math+rus+info) / 3
где math = Сумма всех математик по школе / StatsCount
rus = Сумма всех языков по школе / StatsCount
info = Сумма всех информатик по школе / StatsCount
Ввод школ
Создать новый список
По каждой статистике по школе. Если нет в новым списке то добавить. Если есть то сложить статистики и увеличить StatsCount.
Вывести новый список.
У вас проблемы не с алгоритмом, а с базовыми принципами программирования (для начала почитайте про GRASP), в т.ч. с ООП. Вы написали абсолютно не читаемый код на очень тривиальной задаче, в котором не смогли разобраться даже сами. А ведь по сути задача сводилась к поиску среднего арифметического. Для начала запомните, что машина прочитает любой код. Главная ваша задача - сделать код читаемым для человека. Именно для этого существуют все парадигмы программирования, паттерны и т.д. Посему читаемость - главное! И первое, что на нее влияет - правила именования, именно поэтому их очень важно соблюдать. Классы пишутся с большой буквы, методы и переменные - с маленькой. Все имена должны быть осмысленные. Если вы написали исключительный код с точки зрения ООП, но при этом ваши переменные называются a,b,c,d, все ваши усилия напрасны и ваш код нужно выбросит в урну по той же причине - это не читаемо! Следующее правило : геттеры и сеттеры - устоявшиеся и общепринятые сигнатуры, посему сеттеры всегда void. Хотите сделать то, что вы сделали, используйте паттерн билдер, но не меняйте сигнатуры общепринятых методов. Причин тому много. Я назову лишь одну (остальные вы поймете со временем): поведение любой построенной вами инженерной системы должно быть интуитивно понятно и ожидаемо. Например, вы хотите перебрать все элементы коллекции. Вы можете пройти обычным циклом и это нормально. Однако вы можете реализовать свой итератор, который будет делать перебор всех элементов каким-то особым способом. Человек, который посмотрит ваш код с обычным циклом, разберет это за секунды. Кастомный итератор же вызовет справедливый вопрос - почему вы сделали именно так? может нужен особый порядок элементов и т.д. это усложнит читаемость. аналогично с геттерами и сеттерами. их сигнатура такая, какая есть. это ожидаемо и предсказуемо. заталкивать туда дополнительную логику либо менять сигнатуру нельзя. Когда усвоите это, перейдите к уже рекомендованному GRASP. а теперь к практике. ваш класс-модель, описывающий школу, в соответствии с паттероном GRASP information expert, обязан иметь все необходимые методы для работы со своими полями (информация обрабатывается там, где хранится). именно поэтому мы щзаставим наш класс считать среднее арифметическое для своих полей и не будем считать и присваивать его из вне. вместе с тем для обработки множества объектов методы одного объекта нам уже не подходят. решений может быть несколько. мы создадим класс-сервис для этих целей. здесь есть 2 метода : один добавляет информацию о новой школе, а второй предоставляет нам готовую информацию о накопившихся объектах (экземплярах класса школа). реализации довольно простые и выглядят так:
import java.util.Locale;
import java.util.stream.DoubleStream;
public class School {
private int number;
private double mathematics;
private double russianLanguage;
private double computerScience;
private double average;
public School(int number, double mathematics, double russianLanguage, double computerScience) {
this.number = number;
this.mathematics = mathematics;
this.russianLanguage = russianLanguage;
this.computerScience = computerScience;
this.average();
}
public final School average() {
this.average = DoubleStream.of(mathematics, russianLanguage, computerScience).average().getAsDouble();
return this;
}
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
public double getMathematics() {
return mathematics;
}
public void setMathematics(double mathematics) {
this.mathematics = mathematics;
}
public double getRussianLanguage() {
return russianLanguage;
}
public void setRussianLanguage(double russianLanguage) {
this.russianLanguage = russianLanguage;
}
public double getComputerScience() {
return computerScience;
}
public void setComputerScience(double computerScience) {
this.computerScience = computerScience;
}
public double getAverage() {
return average;
}
@Override
public String toString() {
return String.format(Locale.ENGLISH,"Школа № " + number + " математика - " +
"%.1f" + " русский язык - " + "%.1f" + " инфрматика - " + "%.1f" + " общий средний балл - " + "%.1f",
mathematics, russianLanguage,computerScience,average);
}
}
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.Map;
import java.util.HashMap;
import java.util.stream.Collectors;
public class SchoolService {
private final Map<Integer, School> schools;
public SchoolService() {
this.schools = new HashMap<>();
}
public SchoolService add(int number, double mathematics, double russianLanguage, double computerScience) {
if (schools.containsKey(number)) {
final School school = schools.get(number);
school.setMathematics(avarage(school.getMathematics(), mathematics));
school.setRussianLanguage(avarage(school.getRussianLanguage(), russianLanguage));
school.setComputerScience(avarage(school.getComputerScience(), computerScience));
school.average();
}
else schools.put(number, new School(number, mathematics, russianLanguage, computerScience));
return this;
}
private double avarage (double...args) {
return Arrays.stream(args).average().getAsDouble();
}
public Collection<School> get() {
return schools.values();
}
public Collection<School> get(Comparator<School> comparator) {
return schools.values().stream().sorted(comparator).collect(Collectors.toList());
}
}
import java.util.Comparator;
public class Main {
public static void main(String[] args) {
new SchoolService()
.add(32, 80d, 80d, 80d)
.add(71, 91d, 89d, 100d)
.add(1, 15d, 60d, 30d)
.add(32, 100d, 100d, 100d)
.add(1, 75d, 99d, 67d)
.add(17, 78d, 87d, 77d)
.add(89, 66d, 54d, 78d)
.get(Comparator.comparingDouble(School::getAverage).reversed())
.forEach(System.out::println);
}
}
теперь все хорошо? с точки зрения бизнесс-логики да, но с точки зрения программирования не совсем. я бы хотел обратить внимание на конструктор класса-модели. он принимает один int и 3 double. это не очень хорошо, потому что можно с легкостью запутаться в порядке параметров. посему, во-первых, попробуйте реализовать свой кастомный билдер для этого класса. во-вторых, наш сервис сейчас сам создает экземпляры класса-модели и принимает в аргументах метода множество параметров (аналогично конструктору). попробуйте решить эту проблему. в-третьих, билдер - не единственный порождающий паттерн. обратите внимание на остальные. главная проблема ооп- создание экземпляра класса. научитесь решать эту проблему - первый шаг в ооп. удачи