[Java] Średnia ocen dla przedmiotów


(felixik) #1

Witam, powoli uczę się javy i napotkałem kilka problemów przy rozwiązywaniu zadania o treści “Napisz program, który policzy średnią z kilku przedmiotów. Możemy założyć, że uczeń w szkole ma 3 przedmioty i z każdego z nich dostał po 4 oceny”. Otóż:

  1. jak policzyć średnią dla każdego przedmiotu osobno?
  2. gdy wpisuję nazwę przedmiotu dłuższą niż 4 znaki pętla kończy wyjątkiem po otrzymaniu 5 oceny (choć po 4 już powinien być kolejny przedmiot).
    Błąd: Exception in thread “main” java.lang.ArrayIndexOutOfBoundsException: 4
    at Lesson6.Ex1.PobierzPrzedmiotyIocene(Ex1.java:27)
    at Lesson6.Ex1.main(Ex1.java:40)

Prośba o wskazówki niż gotowca. Z góry dziękuję za pomoc, kod poniżej

import java.util.Scanner;

class Ex1 {
    private String name;
    private String[] subjects = new String[3];
    private float[][] notes = new float[3][4];
    float result;
    Scanner sc = new Scanner(System.in);

    private void PobierzImieOdUsera() {
        System.out.print("Podaj imię ucznia: ");
        name = sc.next();
    }

    private void PobierzPrzedmiotyIocene() {
        for (int i = 0; i < subjects.length; i++) {
            System.out.print("Podaj nazwy przedmiotów, których uczy się " + name + " ");
            subjects[i] = sc.next();
            for (int j = 0; j < subjects[i].length(); j++) {
               System.out.print("Podaj ocenę dla przedmiotu: " + subjects[i] + " ");
               notes[i][j] = sc.nextFloat();
            }
        }
    }

    private void SrednieOcen() {

    }


    public static void main(String[] args) {
        Ex1 n = new Ex1();
        n.PobierzImieOdUsera();
        n.PobierzPrzedmiotyIocene();
        n.SrednieOcen();
    }
}

(Fizyda) #2

Nie mam Javy na kompie ani na żadnej virtualnej maszynie, a nie chce mi się instalować dla jednego przykładu. Pokaż zrzut ekranu przed wystąpieniem błędu.


(krystian3w) #3

https://ideone.com/BdtB5J - możesz spróbować sklonować jako sekretny kod “:dark_sunglasses:

Exception in thread "main" java.util.NoSuchElementException
	at java.util.Scanner.throwFor(Scanner.java:862)
	at java.util.Scanner.next(Scanner.java:1371)
	at Ex1.PobierzImieOdUsera(Main.java:12)
	at Ex1.main(Main.java:33)

(krystian3w) #4

https://ideone.com/wIhjGO - średnia liczona ręcznie, możesz przerobić na pętle by nie wpisywać z palca elementów tablicy.

class Ex1 {
//  . . . . . . . . . . . . . . . . . . . . . . . . 
    private float srednia1, srednia2, srednia3;

//  . . . . . . . . . . . . . . . . . . . . . . . .
    private void SrednieOcen() {
    	srednia1=(notes[0][0]+notes[0][1]+notes[0][2])/3;
    	srednia2=(notes[1][0]+notes[1][1]+notes[1][2])/3;
    	srednia3=(notes[2][0]+notes[2][1]+notes[2][2])/3;
    	System.out.print("Srednia " + subjects[0] +  ": "+ srednia1 + " \n");
    	System.out.print("Srednia " + subjects[1] +  ": "+ srednia2 + " \n");
    	System.out.print("Srednia " + subjects[2] +  ": "+ srednia3 + " \n");
    }
// . . . . . . . . . . . . . . . . . . . . . . . .
}

Ale nadal nie ustaliłem czemu ucina (a właściwie nie dopuszcza) nazwę przedmiotu do 3 liter.

Dodatkowo chyba trzeba rozbudować tablicę (:question:) lub pętle przebudować, nie pozwala na zapisanie 4 przedmiotów ani 4 ocen.


(Fizyda) #5

Nie jestem pewny bo w Javie pisałem tylko na studiach, ale ja bym zrobił reader.nextLine() zamiast reader.next() być może w metodzie wczytywania jest problem.

Możesz zapisać 3 przedmioty i 4 oceny do każdego przedmiotu. Autor chyba się przejęzyczył w jednym miejscu bo takie wartości są też podane w treści zadania. Też się nad tym chwilę zastanawiałem, ale tak wynika z kodu i treści zadania, więc założyłem, że to literówka.


(krystian3w) #6

Tyle, że 4 ocenę przerabia mi na przedmiot np. “2” i się momentalnie program w kompilatorze online przerywa.

Przerobiłem peltę i rozmiar tablicy to nagle źle zaczęło liczyć średnią 4 ocen. Pewnie źle myślę jak to przerobić stąd problem - chyba przeskakuje po 2 ocenie na inną liczbę jak sobie wyświetliłem (pierwsze dwie oceny OK, a kolejne dwie z drugiego przedmiotu).


(Fizyda) #7

Teraz dopatrzyłem się błędu który jest w kodzie autora

for (int j = 0; j < subjects[i].length; j++) {

Nie możemy brać długości subjects[i] bo subjects to tablica stringów z nazwami przedmiotów, a to oznacza, że w tym miejscu mamy zwracaną długość danego stringa - czyli 3 bo zawsze podajesz 3 znakową nazwę.
Dlatego musi być

for (int j = 0; j < notes[i].length; j++) {

Rozwiązuje to też drugi problem którego nie mogłem ogarnąć bez kompilacji kodu, ale teraz już to widzę. Wcześniej mieliśmy błąd index out of bounds gdy podawaliśmy dłuższą nazwę przedmiotu niż 3 znaki bo mogliśmy wstawić tylko 4 oceny, a 3 znaki w stringu to tak naprawdę 4 ponieważ jest jeszcze znak końca linii. Ten błąd powodował, że zamiast wczytać 4 oceny wczytywaliśmy do tablicy 4-ro elementowej tyle ocen z ilu znaków składa się nazwa przedmiotu.

Zmiana w tej linijce co napisałem naprawi wszystkie błędy.

Dodatkowo proponuję użyć stałych do określenia liczby przedmiotów i maksymalnej liczby ocen. W tedy można takie stałe również użyć w pętlach zamiast dynamicznie pobierać długości tablic, kod w tedy będzie czytelniejszy no i jeśli będziemy chcieli zmienić liczbę przedmiotów to tylko w jednym miejscu, a nie w całym kodzie. W ten sposób unikniemy wielu błędów w przyszłości.


(Fizyda) #8

Średnią zapisywałbym też w tablicy i wszystko liczył w podwójnej pętli dynamicznie, mniej więcej tak wyglądałoby w tedy ciało funkcji:

for(int i = 0; i < subjectAverage.length; i++)
{
	float average = 0.0;
	
	for(int j = 0; j < notes[i].length; j++)
		average += notes[i][j];
	
	subjectAverage[i] = average / notes[i].length;
}

(krystian3w) #9

Bez tych nawiasów dla length: https://javastart.pl/static/podstawy-jezyka/tablice-wielowymiarowe/

Chwilę myślałem o co chodzi z błędem w kompilatorze.


(Fizyda) #10

Faktycznie, już poprawiam. Po prostu w różnych środowiskach różnie jest z length, czasami jest wystawiona jako api, a czasem jako public properties. Zależy od konwencji danej biblioteki.


(felixik) #11

Panowie, no prawie działa tylko teraz błąd, o którym pisałem przeniósł się w inne miejsce. A kod wygląda tak:

/*
Napisz program, który policzy średnią z kilku przedmiotów.
Możemy założyć, że uczeń w szkole ma 3 przedmioty i z każdego z nich dostał po 4 oceny
*/
package Lesson6;

import java.util.Scanner;

class Ex1 {
private String name;
private String[] subjects = new String[3];
private float[][] notes = new float[3][4];

Scanner sc = new Scanner(System.in);

private void PobierzImieOdUsera() {
    System.out.print("Podaj imię ucznia: ");
    name = sc.next();
}

private void PobierzPrzedmiotyIocene() {
    for (int i = 0; i < subjects.length; i++) {
        System.out.print("Podaj nazwy przedmiotów, których uczy się " + name + " ");
        subjects[i] = sc.next();
        for (int j = 0; j < notes[i].length; j++) {
           System.out.print("Podaj ocenę dla przedmiotu: " + subjects[i] + " ");
           notes[i][j] = sc.nextFloat();
        }
    }
}

private void SrednieOcen() {
    float subjectAverage[] = new float[4];
    for(int i = 0; i < subjectAverage.length; i++)
    {
        float average = 0;

        for(int j = 0; j < notes[i].length; j++)
            average += notes[i][j];

        subjectAverage[i] = average / notes[i].length;
    }

}


public static void main(String[] args) {
    Ex1 n = new Ex1();
    n.PobierzImieOdUsera();
    n.PobierzPrzedmiotyIocene();
    n.SrednieOcen();
}

}

przy average 0.0 kompilator krzyczał błąd.

Błąd jest w linii for(int j = 0; j < notes[i].length; j++)

Exception in thread “main” java.lang.ArrayIndexOutOfBoundsException: 3
at Lesson6.Ex1.SrednieOcen(Ex1.java:38)
at Lesson6.Ex1.main(Ex1.java:51)


(Fizyda) #13

Musisz mieć wszędzie tą samą liczbę przedmiotów, tutaj nie chodzi o ilość ocen a przedmiotów. Zmień na 3 elementową tablicę.


(felixik) #14

Dzięki. Jutro dorobię jeszcze wyciąganie nazw przedmiotów, bo ładniej będzie. Zobaczymy czy się uda :slight_smile:


(krystian3w) #15

0.0 może zamień na 0.

gotwiec - https://ideone.com/pAflHj