Jump to content

Archived

This topic is now archived and is closed to further replies.

PhoeniX426

Java - zadanie ze SPOJa - problem ze Scannerem

Recommended Posts

Witam! Mam pewien problem. Generalnie od niedawna robię sobie różna zadanka na SPOJu i trafiłem na takie jedno dosyć proste - http://pl.spoj.com/problems/POL/. Udało mi się napisać odpowiedni kod w Javie a mój kompilator wyświetla że wszystko jest w porządku, program się uruchamia. Jednakże SPOJ nie uznał mi tego rozwiązania. Postanowiłem więc że wrzucę kod na ideone.com i tutaj wyświetliło mi błędy. Oto kod programu:

Cytuj

import java.util.Scanner;
public class polowka {

    public static void main(String[] args) {
        Scanner scan_liczba = new Scanner(System.in);
        Scanner scan_napis = new Scanner(System.in);
        String napis;
        String wynik;
        
        //Pobieranie wartości czyli ilości pobieranych napisów
        int a = scan_liczba.nextInt();
        for(int i =0;i<a;i++){
            //Pobieranie napisu
            napis = scan_napis.nextLine();
            
            wynik = napis.substring(0, napis.length()/2);
            System.out.println(wynik);
        }

    }

}

A wyświetla mi błąd:

Cytuj

Exception in thread "main" java.util.NoSuchElementException
	at java.util.Scanner.throwFor(Scanner.java:862)
	at java.util.Scanner.next(Scanner.java:1485)
	at java.util.Scanner.nextInt(Scanner.java:2117)
	at java.util.Scanner.nextInt(Scanner.java:2076)
	at Ideone.main(Main.java:18)

Generalnie nie pasuje mu coś z pobieraniem wartości. Wcześniej robiłem też kilka zadań i problem też się pojawiał. Co właściwie robię źle? Proszę o pomoc.

PS. Programuje w Jave dopiero od paru dni więc proszę o wyrozumienie :)

PS2. Tutaj zamieszczam kod na ideone: https://ideone.com/pulwXf

Link to comment
Share on other sites

Szczerze, to nie mam pojęcia, czemu program wysypuje się w tej konkretnej linijce, ale tak czy siak nie ma prawa działać w pełni poprawnie - metoda nextInt odczytuje jedynie najbliższą liczbę i zostawia w strumieniu znak nowej linii. Stąd lepszym pomysłem byłoby odczytanie całej linii (nextLine) i następnie wydobycie z niej wartości liczbowej z pomocą metody Integer.parseInt.

I tak swoją drogą - po co Ci dwa obiekty klasy Scanner?

Link to comment
Share on other sites

Cytuj

I tak swoją drogą - po co Ci dwa obiekty klasy Scanner?

Wcześniej kiedy miałem jeden obiekt Scanner to kompilator pokazywał błąd. Używałem jednego obiektu by pobrać wartość integer dla pętli za pomocą nextInt, a następnie tego samego obiektu by pobrać wartość string to kompilatorowi coś nie pasowało. Teoretycznie ja wiem że nie potrzeba dwóch ale nie potrafiłem odgadnąć na czym polegał błąd. Drugi skaner pomógł. W każdym razie w powyższym zadaniu usunąłem drugi Scanner.

Czy zawsze kiedy pobieramy wartości liczbowe to jest lepiej używać nextLine a potem Integer.parseInt? Kiedy się bardziej przydaje nextInt?

Cytuj

Stąd lepszym pomysłem byłoby odczytanie całej linii (nextLine) i następnie wydobycie z niej wartości liczbowej z pomocą metody Integer.parseInt.

Poprawiłem kod tak jak zaproponowałeś. Ideone dalej wyświetla błąd ale już SPOJ zaakceptował zadanie. Dzięki wielki za pomoc :D

Tutaj zamieszczam poprawiony kod: https://ideone.com/6UuvYI

Chyba fatycznie chodziło o nextInt'a.

Mam natomiast jeszcze jedno pytanie. Wiele zadań na SPOJu z jakimi się zetknąłem wymagało by na wejściu (kiedy wymagano liczb) podawano zestaw liczb oddzielonych spacjami. Np tak jak w zadaniu http://pl.spoj.com/problems/PRZEDSZK/

Generalnie poradziłem sobie w ten sposób:

Cytuj

Scanner scan_napis = new Scanner(System.in);
String linia = scan_napis.nextLine();
String[] numbers = linia.split(" ");
int[] intNumbers = new int[numbers.length];
        
for(int i = 0;i<numbers.length;i++){
      intNumbers = Integer.parseInt(numbers);
}

Tworzyłem zmienną String która pobiera ciąg liczb jako napis. Następnie tworzyłem tablicę typu string i używałem funkcji split(" ") by oddzielone znaki za pomocą spacji wpisywało do tej tablicy. Potem już tylko tworzyłem tablicę int o długości poprzedniej tablicy i przepisywałem wartości używając  Integer.parseInt. Czy ten sposób jest właściwy? Generalnie działa ale czy można to zrobić lepiej?

Link to comment
Share on other sites

52 minuty temu, PhoeniX426 napisał:

Ideone dalej wyświetla błąd ale już SPOJ zaakceptował zadanie.

Ok, to już wszystko jasne - w przypadku Ideone musisz samodzielnie wpisać tekst, jaki pojawi się na standardowym wejściu. Jeżeli jest on pusty, to Scanner nie ma nic do odczytania i rzuca błędem.

52 minuty temu, PhoeniX426 napisał:

Kiedy się bardziej przydaje nextInt?

Może inaczej - pobieranie i parsowanie całej linii przydaje się w tym konkretnym przypadku, gdy w całej linii jest tylko pojedyncza wartość.

52 minuty temu, PhoeniX426 napisał:

Tworzyłem zmienną String która pobiera ciąg liczb jako napis. Następnie tworzyłem tablicę typu string i używałem funkcji split(" ") by oddzielone znaki za pomocą spacji wpisywało do tej tablicy. Potem już tylko tworzyłem tablicę int o długości poprzedniej tablicy i przepisywałem wartości używając  Integer.parseInt. Czy ten sposób jest właściwy? Generalnie działa ale czy można to zrobić lepiej?

Tu z kolei wygodniejsze byłoby użycie nextInt - Scanner sam pominie białe znaki.

53 minuty temu, PhoeniX426 napisał:

Wcześniej kiedy miałem jeden obiekt Scanner to kompilator pokazywał błąd.

Błąd, czy ostrzeżenie? Ostrzeżenie mogłoby wynikać z niezamkniętego Scannera, choć akurat w przypadku, gdy wewnętrznym strumieniem jest System.in, to sytuacja jest ciut utrudniona (klik).

Link to comment
Share on other sites

Cytuj

Błąd, czy ostrzeżenie?

Z tego co pamiętam to był błąd. W trakcie kompilacji wyświetlał błąd w pobieraniu wartości w wierszu z użyciem nextLine. Odniosłem wrażenie że nie podoba mu się to że obiekt typu scanner był wykorzystany najpierw do pobrania zmiennej typu Integer a potem zmiennej typu String. Dodałem więc nowego Scannera i jakoś zadziałało, myślałem więc że w tym był problem. Nie jestem też pewien czy była to wina niezamknięcia Scannera bo generalnie Eclipse wyświetla mi na boku ostrzeżenie że nie został on zamknięty, poza tym w innych programach niezamknięty Scanner wciąż działał i poza ostrzeżeniem nic nie wypisywał.

Cytuj

Tu z kolei wygodniejsze byłoby użycie nextInt - Scanner sam pominie białe znaki.

Czyli mógłbym od razu wpisać dane wejściowe do tablicy Integer, dobrze myślę? Z resztą zaraz to wypróbuje.

Jeszcze raz dzięki za pomoc. Dzięki twojej radzie przeszło mi jeszcze kilka zadań które miałem zrobione ale SPOJ je odrzucał :D

Link to comment
Share on other sites

Dnia 4.02.2017 o 21:44, PhoeniX426 napisał:

Nie jestem też pewien czy była to wina niezamknięcia Scannera bo generalnie Eclipse wyświetla mi na boku ostrzeżenie że nie został on zamknięty, poza tym w innych programach niezamknięty Scanner wciąż działał i poza ostrzeżeniem nic nie wypisywał.

Ogólnie dobrą praktyką jest zamykanie tego, co wcześniej się otworzyło. To pozwala uniknąć wycieku zasobów. Przy czym zamknięcie obiektu klasy Scanner powoduje zamknięcie znajdującego się pod nim strumienia. To sprawia, że wszystkie obiekty Scanner, które korzystają z tego samego strumienia również nie będą mogły z niego korzystać. Czyli Scanner należy zamykać po tym jak wszystkie Scannery korzystające z tego samego strumienia przestaną działać. Dodatkowo domyślnie Scanner jest podpięty do standardowego wejścia, a tego nie chcesz zamykać przed końcem działania programu.

W tym przypadku najlepiej zamknąć Scanner w bloku finally, czyli coś takiego:

 

Scanner sc = new Scanner(file);
try {
    while (sc.hasNextLine()) {
        //kod
    }
} finally {
    sc.close();
}

W nowszych wersjach Javy można użyć konstrukcji try-with-resources:

try (Scanner sc = new Scanner(file)) {
    while (sc.hasNextLine()) {
        //kod
    }
}

 

 

Link to comment
Share on other sites



  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...