Avatar
Impuls
Člen
Avatar
Impuls:

Ahoj, potřeboval bych poradit proč mi můj kód hlásí chyby v metodě najdiSlovo. Mám to do školy a program by mě najít slovo, které je ve vstupním souboru nejčastěji opakované. Pokud by někdo věděl jak to naprogramovat líp tak budu jenom rád. :)

package SemPrace;

import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

/**
 * Created by Michal on 2.12.2015.
 */
public class Slova {

    public static void najdiSlovo(List<String> seznam) {
        String porovnavaneSlovo;
        int pocetVyskytu = 0;
        String nejcastejsiSlovo = null;
        int nejvetsiPocet = 0;
        for (int i = 0; i < seznam.size(); i++) {
            porovnavaneSlovo = seznam.get(i);
            for (int j = 0; i < seznam.size(); j++) {
                if (porovnavaneSlovo == seznam.get(j)) {
                    pocetVyskytu++;
                }
            }
            if (pocetVyskytu > nejvetsiPocet) {
                nejvetsiPocet = pocetVyskytu;
                nejcastejsiSlovo = porovnavaneSlovo;
            }
        }
        System.out.println("Nejcasteji opakovane slovo je: " + nejcastejsiSlovo + " a vyskytuje se tam " + nejvetsiPocet + "krat.");
    }

    public static void main(String[] args) throws IOException {
        List<String> seznamSlov = new ArrayList<>();
        Scanner sc = new Scanner(System.in);

        System.out.println("Zadejte jmeno vstupního souboru: ");
        String jmenoVstupSouboru = sc.nextLine();

        File vstup = new File(jmenoVstupSouboru);

        if (vstup.exists()) { //pokud vstupní soubor existuje
            FileReader fr = new FileReader(vstup);
            BufferedReader br = new BufferedReader(fr);

            while (br.ready()) { //dokud má co číst
                String radek = br.readLine(); //v souboru čte po řádkách
                seznamSlov.add(radek); //přidává je do ArrayListu
            }
            najdiSlovo(seznamSlov);
        }
    }
}
 
Odpovědět 2.12.2015 15:52
Avatar
Lukas C#
Redaktor
Avatar
Odpovídá na Impuls
Lukas C#:

Tak jedna chyba je ve druhém cyklu - nemělo by tam být "j < seznam.Size()" místo "i < seznam.Size()"?

 
Nahoru Odpovědět 2.12.2015 16:06
Avatar
tomisoka
Redaktor
Avatar
Odpovídá na Impuls
tomisoka:

Kvůli tomuto:
for (int j = 0; i < seznam.size(); j++) {

Mimochodem hodilo by se tam přidat toto:

pocetVyskytu=0;
Akceptované řešení
+20 Zkušeností
+1 bodů
Řešení problému
 
Nahoru Odpovědět 2.12.2015 16:09
Avatar
Impuls
Člen
Avatar
Odpovídá na tomisoka
Impuls:

Jo díky moc vůbec nevím jak se to tam dostalo.

 
Nahoru Odpovědět 2.12.2015 16:15
Avatar
Impuls
Člen
Avatar
Odpovídá na tomisoka
Impuls:

Tak ještě bych potřeboval poradit. Spustil sem debug file a pokaždé mi to vypisuje u proměnné pocetVyskytu 1. Nevíš v čem by mohla být ještě chyba?

 
Nahoru Odpovědět 2.12.2015 17:30
Avatar
B42P6
Člen
Avatar
Odpovídá na Impuls
B42P6:

Môžeš to zjednodušiť tak, že miesto for cyklu použiješ foreach cyklus. ;)

Nahoru Odpovědět 3.12.2015 17:22
'long long long' is too long for GCC
Avatar
David Hanina
Člen
Avatar
Odpovídá na Impuls
David Hanina:

Ahoj, nejsem si jist, jak je to u javy ale typl bych, že je to tím, že přidáváš do slovníku celé věty a né slova

String radek = br.readLine();
seznamSlov.add(radek);

viz tyto řádky, myslím že nejdříve musíš řádek rozdělit do slov..

 
Nahoru Odpovědět 3.12.2015 17:58
Avatar
Impuls
Člen
Avatar
Odpovídá na B42P6
Impuls:

Jako myslíš místo toho vnořeného for cyklu? Nebo teď to moc nechápu.

 
Nahoru Odpovědět 4.12.2015 12:30
Avatar
David Hanina
Člen
Avatar
Odpovídá na Impuls
David Hanina:
for (int i = 0; i < seznam.size(); i++) == foreach i in seznam

ale je to drobnost, používet to, co ti víc sedne

Editováno 4.12.2015 14:49
 
Nahoru Odpovědět 4.12.2015 14:46
Avatar
B42P6
Člen
Avatar
Odpovídá na Impuls
B42P6:

Foreach cyklus je upravený for cyklus ktorý sám prejde prvky v poli. Takže miesto

for (int i = 0; i < seznam.size(); i++) {
           porovnavaneSlovo = seznam.get(i);

           }

máš

for (String porovnavaneSlovo:seznam) {

    }

http://www.itnetwork.cz/…utorial-pole

Nahoru Odpovědět 4.12.2015 14:47
'long long long' is too long for GCC
Avatar
Jaro
Člen
Avatar
Odpovídá na B42P6
Jaro:

Doplním, že foreach je o niečo rýchlejší ako klasický for a na to aby sa dal použiť foreach, musí daná kolekcia implementovať interface Enumerable, ak si správne pamätám. Používa sa keď potrebuješ iba hodnoty prvkov a nepotrebuješ meniť pôvodné hodnoty v poli/kolekcii

Nahoru Odpovědět  ±0 4.12.2015 16:29
A ship is safe in harbor. But then again, that´s not what ships are for.
Avatar
B42P6
Člen
Avatar
Odpovídá na Jaro
B42P6:

No, niekde som čítal že foreach je pomalší ,ale to je úplne zanedbateľne v porovnaní s tým že je to potom prehľadnejšie . A asi si myslel interface Enumeration, ale to sa použiť iba na klasický for (https://docs.oracle.com/…eration.html). Na to aby sa dal použiť foreach sa musí implementovať interface Iterable. ;)

Nahoru Odpovědět 4.12.2015 18:54
'long long long' is too long for GCC
Avatar
Taskkill
Redaktor
Avatar
Odpovídá na Jaro
Taskkill:

Panove, foreach neni ani rychlejsi a ani neni zanedbatelne pomalejsi... nikdy bych ho nedpoporucil pouzivat v zadnem jazyce na zadne platforme, pokud nejste dohnani jedinou moznou vyjimkou k tomuto nouzovemu reseni ( a to kuprikladu faktem, ze proste nejste schopni zjistit kolik jednotek v kolekci bude... treba pokud se nejak nerozumne meni pocet prvku v kolekci) ... jestli chcete delat programy co budou za neco stat musite myslet na rezii... nejde si jen tak rict ze milisekunda tam milisekunda sem to nikoho neboli... tenhle pristup nejde praktikovat.. jinak samozrejme no-offense :)

 
Nahoru Odpovědět  -2 4.12.2015 21:40
Avatar
Odpovídá na Taskkill
Petr Čech (czubehead):

Pokud vím, tak foreach se zkompiluje na for, takže vaše diskuze je zcela zbytečná.
Názor nepoužívat foreach je taktéž zcestný, protože výrazně zlepšuje přehlednost kódu (ve většině případů), proto ho také máme. Nemyslím si, že by inženýři navrhující většinu programovacích jazyků přidali nějaké zbytečné zpomalovátko, to nedává smysl ;-)

Nahoru Odpovědět  +3 4.12.2015 21:45
Why so serious? -Joker
Avatar
Jaro
Člen
Avatar
Odpovídá na Taskkill
Jaro:

Foreach je trošku rýchlejší, lebo počíta veľkosť pola iba raz (čo sa dá samozrejme dosiahnuť aj pri for cykle ofc), a mne teda príde častokrát omnoho lepšie čitateľný ako klasický for + pri foreachi je záruka, že nikde v tom cykle sa nemenia hodnoty tej danej kolekcie

Nahoru Odpovědět  +1 4.12.2015 22:43
A ship is safe in harbor. But then again, that´s not what ships are for.
Avatar
Taskkill
Redaktor
Avatar
Odpovídá na Petr Čech (czubehead)
Taskkill:

Zasadni je podle me myslenka, ze inzenyri co navrhli cecko nenevrhovali javu...
Ja budu uplne spokojenej kdyz si tenhle kod spustite na vasich masinach a parkrat se kouknete na vystup..rekneme desetkrat...dva­cetkrat ... padesatkrat... tak jako jsem to udelal ja...
bezi to vzdy jen jednou, protoze JVM ma celkem slusne vymyslenou optimalizaci za behu...prece jenom nejsou to zadni sumari lidi co to delaj... rekneme ze bezne male pole, i s interakci s prvkem dostatecne demonstruje co je rychlejsi a o kolik... jestli mi nekdo z tech, co se mnou nesouhlasi nebo Jakub, ktery mi jen dal minus a nevyjadril se vysvetli proc tomu tak je a ukaze se, ze jsem se zmylil rad si znovu prostuduju materialy a projdu dokumentaci na netu.

public static void main(String[] args) {

        long time1;
        long time2;
        long time3;
        long time4;

        int[] experArr = new int[100000000];
        for (int i = 0; i < experArr.length; i++) {
            experArr[i] = i;
        }

        time3 = System.nanoTime();
        for (int item : experArr) {
            //System.out.println(item);
        }
        time4 = System.nanoTime();

        time1 = System.nanoTime();
        for (int e = 0; e < experArr.length; e++) {
            //System.out.println(pole[i]);
        }
        time2 = System.nanoTime();

        System.out.println("for: " + (time2 - time1));
        System.out.println("foreach: " + (time4 - time3));

        if ((time2 - time1) < (time4 - time3)) {
            System.out.println("for je rychlejsi presne o: " + ((time4 - time3) - (time2 - time1)) + " nanosekund");
        }
        if ((time2 - time1) > (time4 - time3)) {
            System.out.println("foreach je rychlejsi presne o: " + ((time2 - time1) - (time4 - time3)) + " nanosekund");
        }
    }
 
Nahoru Odpovědět 5.12.2015 0:34
Avatar
Taskkill
Redaktor
Avatar
Odpovídá na Petr Čech (czubehead)
Taskkill:

Ja presne nevim co na tomhle miste rict... ano typek to na SO popsal moc hezky... fakt bych tomu i veril, kdyby ovsem test neukazal neco jineho... na deset pokusu pripada asi 8 - 9 kdy je for rychlejsi o radove 10−7 sekundy ... idk ... neni to moc dulezity tak to necham byt ...

 
Nahoru Odpovědět  +1 5.12.2015 1:06
Avatar
Impuls
Člen
Avatar
Impuls:

Díky za rady ale foreach sem nikdy nepoužíval, tak si to nechám radši tak jak to mám.

 
Nahoru Odpovědět 5.12.2015 9:02
Avatar
Odpovídá na Taskkill
Jakub Šárník:

Mínus jsem ti dal za "doporučení" nepoužívat foreach, protože prostě postrádá logiku.

 
Nahoru Odpovědět 5.12.2015 16:10
Avatar
Hartrik
Redaktor
Avatar
Odpovídá na Taskkill
Hartrik:

Foreach je hlavně o srozumitelnějším a přehlednějším zápisu, což je obecně důležitější. Ještě jsem nikdy neslyšel, že by ho někdo nedoporučoval, spíš naopak.

Pokud by někomu šlo výkon, tak by jistě nasadil JIT, který prý umí foreach lépe optimalizovat. Myslím, že jsem to slyšel zde: http://java.cz/…ava-aplikaci

Navíc je ten tvůj testovací kód špatně, fori totiž nepřistupuje k prvkům pole, zatímco foreach ano.

 
Nahoru Odpovědět  +1 5.12.2015 16:53
Avatar
coells
Redaktor
Avatar
Odpovídá na Taskkill
coells:

Miluju tyhle dětské benchmarky i to, jak se v nich dá podvádět.
Vzal jsem tvůj kód a trochu ho upravil do rigoróznější podoby.

Výsledek (hodnota je, kolik se stihlo udělat cyklů v časovém rozmezí):

$ java -version
java version "1.8.0_31"
Java(TM) SE Runtime Environment (build 1.8.0_31-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.31-b07, mixed mode)
$ java test
for: 20 < foreach: 21
for: 42 < foreach: 199
for: 20 > foreach: 19
for: 51 < foreach: 203
for: 21 < foreach: 21
for: 202 < foreach: 202
for: 6 < foreach: 21
for: 50 < foreach: 201
for: 21 < foreach: 21
for: 197 < foreach: 204
for: 6 < foreach: 20
for: 51 < foreach: 201
for: 20 < foreach: 21
for: 200 > foreach: 199
for: 5 < foreach: 20

Můj kód pro replikaci výsledků:

public class test
{
public static void main(String[] args) {

        int[] experArr = new int[100000000];
        for (int i = 0; i < experArr.length; i++) {
            experArr[i] = i;
        }

        while(true) {
            iterate(1000000000L, experArr);
            iterate(10000000000L, experArr);
            iterate2(1000000000L, experArr);
            iterate2(10000000000L, experArr);
        }
}

private static void iterate(long K, int[] list) {
        long time1;
        long time2;
        long time3;
        long time4;

        int cycles1 = 0;
        int sum1 = 0;
        time3 = System.nanoTime();
        do {
            for (int item : list) {
                sum1 += item;
            }
            cycles1++;
            time4 = System.nanoTime();
        }
        while (time4 - time3 < K);

        int cycles2 = 0;
        int sum2 = 0;
        time1 = System.nanoTime();
        do {
            for (int e = 0; e < list.length; e++) {
                sum2 += list[e];
            }
            cycles2++;
            time2 = System.nanoTime();
        }
        while (time2 - time1 < K);

        System.out.print("for: " + cycles2);
        System.out.print(cycles1 >= cycles2 ? " < " : " > ");
        System.out.println("foreach: " + cycles1);
    }

private static void iterate2(long K, int[] list) {
        long time1;
        long time2;
        long time3;
        long time4;

        int cycles1 = 0;
        int sum1 = 0;
        time3 = System.nanoTime();
        do {
            for (int item : list) {
                sum1 += item;
            }
            cycles1++;
            time4 = System.nanoTime();
        }
        while (time4 - time3 < K);

        int cycles2 = 0;
        int sum2 = 0;
        time1 = System.nanoTime();
        do {
            for (int e = 0; e < list.length; e++) {
                sum2 += list[e];
            }
            cycles2++;
            time2 = System.nanoTime();
        }
        while (time2 - time1 < K);

        System.out.print("for: " + cycles2);
        System.out.print(cycles1 >= cycles2 ? " < " : " > ");
        System.out.println("foreach: " + cycles1);
    }
}
 
Nahoru Odpovědět 5.12.2015 18:45
Avatar
Odpovídá na coells
Libor Šimo (libcosenior):

Zaujímavé, takže foreach je v priemere rýchlejšie ako for. :-)

Nahoru Odpovědět 5.12.2015 19:17
Aj tisícmíľová cesta musí začať jednoduchým krokom.
Avatar
Odpovídá na coells
Libor Šimo (libcosenior):

Pozrel som si tvoj kód trochu podrobnejšie, ale foreach tam vôbec netestuješ, alebo mi niečo ušlo?

Nahoru Odpovědět 5.12.2015 19:21
Aj tisícmíľová cesta musí začať jednoduchým krokom.
Avatar
coells
Redaktor
Avatar
Odpovídá na Libor Šimo (libcosenior)
coells:

To netvrdím, jen umím napsat benchmark, kterým to jde dokázat.
Stejně tak můžu napsat benchmark, který dokáže opak - proto tomu říkám "dětské" benchmarky.

Rychlejší (v Javě) je v situacích, o kterých se píše na SO (odkaz výše), ale s tím tyhle benchmarky vůbec nesouvisí.
Naproti tomu v Objective-C jsou fast enumeratory rychlejší než indexované cykly, ale důvod je za hranicí toho, abych to mohl vysvětlit.

Editováno 5.12.2015 19:28
 
Nahoru Odpovědět  +2 5.12.2015 19:26
Avatar
Taskkill
Redaktor
Avatar
Odpovídá na coells
Taskkill:

Jak vidim, nemel jsem uplne pravdu ... pripoustim, ze moje nevrazivost vuci foreach je na tomhle miste opravdu zbytecna, sveho casu jsem u starsi verze javy cetl, ze je pomalejsi a informaci jsem si ponechal doted... beru to zpet... koneckoncu chybama se clovek uci... takze diky za vase informace, cenim si vaseho vstricneho (a do znacne miry i pratelskeho) pristupu

 
Nahoru Odpovědět 5.12.2015 23:59
Avatar
coells
Redaktor
Avatar
Odpovídá na Taskkill
coells:

V době, kdy to ten člověk psal, byla pomalá celá java a dotyčný zřejmě nedokázal docenit výhody for-each zápisu.

Tys udělal jedinou chybu, a tou bylo, že jsi nezužitkoval výsledky svého testu.
Můžeš si to zkusit, jak se to dělá doopravdy:

  1. udělej si testy, které poběží alespoň 10 sekund (a nebudeme to kompikovat statistikou)
  2. každý postup musíš mít v jednom programu (netestovat oba naráz)
  3. spusť test na několika různých počítačích (zejména odlišných architekturách)
  4. udělej si grafy, kde osa X vyjadřuje procenta od 0 do 100, kolik z celkového času reálného algoritmu zabírá samotný cyklus

Tam uvidíš relativní hodnoty a dozvíš se, kolik sekund ušetříš při hodinovém běhu.
Když pak porovnáš rozdíly časů, dozvíš se například, že zisk v praxi je 0.5 sekundy na 1 hodinu.

Zlaté pravidlo zní, pokud potřebuješ hodnoty indexů, tak for-cyklus, jinak vždy for-each.

 
Nahoru Odpovědět  +2 6.12.2015 3:13
Avatar
Taskkill
Redaktor
Avatar
Odpovídá na coells
Taskkill:

Myslim, ze chapu .... a nakonec jsem docela rad, ze jsem se do te diskuze pustil, tenhle poznatek rozhodne zuzitkuju ... dik

 
Nahoru Odpovědět 6.12.2015 11:26
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 28 zpráv z 28.