IT rekvalifikace s garancí práce. Seniorní programátoři vydělávají až 160 000 Kč/měsíc a rekvalifikace je prvním krokem. Zjisti, jak na to!
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.

Diskuze: Pomoc s programem

Aktivity
Avatar
Impuls
Člen
Avatar
Impuls:2.12.2015 15:52

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
Odpovídá na Impuls
Neaktivní uživatel:2.12.2015 16:06

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
Neaktivní uživatelský účet
Avatar
tomisoka
Tvůrce
Avatar
Odpovídá na Impuls
tomisoka:2.12.2015 16:09

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í
+2,50 Kč
Řešení problému
 
Nahoru Odpovědět
2.12.2015 16:09
Avatar
Impuls
Člen
Avatar
Odpovídá na tomisoka
Impuls:2.12.2015 16:15

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:2.12.2015 17:30

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:3.12.2015 17:22

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
Odpovídá na Impuls
Neaktivní uživatel:3.12.2015 17:58

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
Neaktivní uživatelský účet
Avatar
Impuls
Člen
Avatar
Odpovídá na B42P6
Impuls:4.12.2015 12:30

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
Odpovídá na Impuls
Neaktivní uživatel:4.12.2015 14:46
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
Neaktivní uživatelský účet
Avatar
B42P6
Člen
Avatar
Odpovídá na Impuls
B42P6:4.12.2015 14:47

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:4.12.2015 16:29

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
4.12.2015 16:29
“What would you do if you were 100% sure you couldn’t fail?”
Avatar
B42P6
Člen
Avatar
Odpovídá na Jaro
B42P6:4.12.2015 18:54

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
Odpovídá na Jaro
Neaktivní uživatel:4.12.2015 21:40

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
4.12.2015 21:40
Neaktivní uživatelský účet
Avatar
Petr Čech
Tvůrce
Avatar
Odpovídá na Neaktivní uživatel
Petr Čech:4.12.2015 21:45

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
4.12.2015 21:45
the cake is a lie
Avatar
Jaro
Člen
Avatar
Odpovídá na Neaktivní uživatel
Jaro:4.12.2015 22:43

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
4.12.2015 22:43
“What would you do if you were 100% sure you couldn’t fail?”
Avatar
Odpovídá na Petr Čech
Neaktivní uživatel:5.12.2015 0:34

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
Neaktivní uživatelský účet
Avatar
Odpovídá na Petr Čech
Neaktivní uživatel:5.12.2015 1:06

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
5.12.2015 1:06
Neaktivní uživatelský účet
Avatar
Impuls
Člen
Avatar
Impuls:5.12.2015 9:02

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 Neaktivní uživatel
Neaktivní uživatel:5.12.2015 16:10

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
Neaktivní uživatelský účet
Avatar
Hartrik
Tvůrce
Avatar
Odpovídá na Neaktivní uživatel
Hartrik:5.12.2015 16:53

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
5.12.2015 16:53
Avatar
coells
Tvůrce
Avatar
Odpovídá na Neaktivní uživatel
coells:5.12.2015 18:45

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):5.12.2015 19:17

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):5.12.2015 19:21

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
Tvůrce
Avatar
Odpovídá na Libor Šimo (libcosenior)
coells:5.12.2015 19:26

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
5.12.2015 19:26
Avatar
Odpovídá na coells
Neaktivní uživatel:5.12.2015 23:59

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
Neaktivní uživatelský účet
Avatar
coells
Tvůrce
Avatar
Odpovídá na Neaktivní uživatel
coells:6.12.2015 3:13

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
6.12.2015 3:13
Avatar
Odpovídá na coells
Neaktivní uživatel:6.12.2015 11:26

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
Neaktivní uživatelský účet
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.