Dubbio in merito a calcolo occorrenze

di il
11 risposte

Dubbio in merito a calcolo occorrenze

Salve ragazzi ho un dubbio, questo è il testo dell'esercizio:

Scrivere un’applicazione che letta una stringa s derivi il numero di occorrenze di ciascuna lettera in s.
Per contare le occorrenze, utilizzare un array di lunghezza pari all’alfabeto occidentale (dalla 'a' alla 'z').

> java Occorrenze
Inserisci la stringa da analizzare: aiuola
occorrenze di a : 2
occorrenze di i : 1
occorrenze di l : 1
occorrenze di o : 1
occorrenze di u : 1


E questa è la soluzione:


        public static void main(String[]args)
        {
            String str = "elefante";

            // Conto le occorrenze
            int[] count = new int['z' - 'a' + 1];
           for (int i = 0; i < str.length(); i++) {
                char c = str.charAt(i);
             
                count[c - 'a']++;
            }
            // Stampo le occorrenze
            for (int i = 0; i < count.length; i++) {
                if (count[i] > 0) {
                    System.out.println((char)('a' + i) + ": " + count[i]);
                }
            }


        }
    }
    RESTITUISCE:
a: 1
e: 3
f: 1
l: 1
n: 1
t: 1

Vorrei però ben capire come funziona l'array count.
Mi è chiaro che nella sua dichiarazione (int[] count = new int['z' - 'a' + 1] rappresenta il codice riferito a tutte le lettere dell'alfabeto dalla a alla z.
Però non ho ben capito il funzionamento.
Per esempio. All'interno del ciclo for, la linea "count[c-'a']++ cosa fa esattamente? prende la lettera corrispondente alla i del ciclo ma perchè la sottrae alla prima lettera dell'alfabeto e incrementa?.

Poi nella stampa del risoltato: com'è stato possibile eludere tutte le lettere dell'alfabeto non inerenti alla parola?.
Come vedete ho molti dubbi spero possiate aiutarmi grazie

11 Risposte

  • Re: Dubbio in merito a calcolo occorrenze

    'z' —'a' leggilo come

    Ordinale di 'z' — ordinale di 'a'

    Idem per c — 'a'

    Il trucco è tutto qui
  • Re: Dubbio in merito a calcolo occorrenze

    sspintux ha scritto:


    'z' —'a' leggilo come

    Ordinale di 'z' — ordinale di 'a'

    Idem per c — 'a'

    Il trucco è tutto qui
    Continua a non essermi chiaro...
    cioè praticamente mi stai dicendo che è come se sottraessi la posizione di z alla posizione di a?
    se ipoteticamente z è 26 e a è 1: 26-1=25?...

    Non riesco a capire come lavora questo codice...
  • Re: Dubbio in merito a calcolo occorrenze

    Anonimamente22 ha scritto:



    cioè praticamente mi stai dicendo che è come se sottraessi la posizione di z alla posizione di a?
    se ipoteticamente z è 26 e a è 1: 26-1=25?...
    si

    ... se fai un pò di debug lo vedi facilemnte come funziona;
    IMOH, può essere istruttivo anche 'eseguire' il codice con carta gomma e matita
  • Re: Dubbio in merito a calcolo occorrenze

    sspintux ha scritto:


    Anonimamente22 ha scritto:



    cioè praticamente mi stai dicendo che è come se sottraessi la posizione di z alla posizione di a?
    se ipoteticamente z è 26 e a è 1: 26-1=25?...
    si

    ... se fai un pò di debug lo vedi facilemnte come funziona;
    IMOH, può essere istruttivo anche 'eseguire' il codice con carta gomma e matita
    Comincio a vedere la luce ma ancora non mi è chiara una cosa.
    Provo a dirti passo per passo cosa ho capito correggimi se sbaglio cortesemente:

    1) int[] count = new int['z' - 'a' + 1]; assegno l'indice al mio vettore pari al numero di lettere dell'alfabeto: cioè 26 (avrei anche potuto scrivere direttamente 26 giusto?)

    2)
        for (int i = 0; i < str.length(); i++) {
                    char c = str.charAt(i);
                    count[c - 'a']++;
                }
                
    Qui si ha un ciclo iterato per tutta la lunghezza della parola, dove verrà assegnata a una variabile char ogni lettera della parola stessa.
    Mentre nel count[c-'a']++; verrà sottratta la posizione della lettera nella variabile char dalla prima lettera dell'alfabeto.
    Quindi se io avessi per esempio
    char c= 'c'; (cioè la lettera c dell'alfabeto).
    La posizione di c sarebbe 3 numericamente, quindi il calcolo fatto è: 3-1=2. E poi all'interno dell'array nella posizione 2 vi sarà un incremento di 1 corrispondente allla lettera dell'alfabeto.

    3)
    
       for (int i = 0; i < count.length; i++) {
                    if (count[i] > 0) {
                        System.out.println((char)('a' + i) + ": " + count[i]);
                    }
                }
    
    
    Avremo un ciclo che si itererà per la dimensione dell'array count. E quindi fino a 26.(avrei potuto scrivere i<26 direttamente giusto?-
    All'interno di questo ciclo avremo un if che si occuperà di far stampare solo le lettere che effettivamente sono comprese nella parola.
    Per quanto riguarda il println: System.out.println((char)('a' + i) + ": " + count);
    Non capisco il perchè scrivere (char) prima di ('a'+i). Non avremmo funzionato in egual modo anche senza?
  • Re: Dubbio in merito a calcolo occorrenze

    Non 3-1=2 ma 99-97=2

    Non hai ancora chiaro il ruolo del codice ASCII in questo programma
  • Re: Dubbio in merito a calcolo occorrenze

    oregon ha scritto:


    Non 3-1=2 ma 99-97=2

    Non hai ancora chiaro il ruolo del codice ASCII in questo programma
    Sisi, so bene cos'è la codifica ASCII cercavo solo di semplifcarlo nella mia testa di .
    Però ora penso di aver capito tutto.
    Quella sottrazione serve solo per rispettare il limite d'indice di 26.
    Dove ogni posizione rappresenta la lettera corrispondente dell'alfabeto tipo count[0]=1 me lo devo immaginare come c'è una sola lettera a.
    Mi è chiaro...
    Sempre in merito alle occorrenze mi permetto di chiederti un'altra cosa senza aprire un nuovo topic:


    Dovendo contare questa volta ogni singola occorenza anche in più parole:
    
    
        public static void main(String[]args)
        {
            String parolaTest="aa bb c";
    
    
    List<String> tt2= new ArrayList<String>(Arrays.asList(parolaTest.split("")));
    HashSet <String> parole =new HashSet<String>(tt2);
    
            System.out.println(parole);
            for(String s:parole) {
                System.out.println(s+ ": "+Collections.frequency(tt2, s));
            }
        }
    }
    
    
    Sono riuscito a realizzare questo codice che funziona. Solo che siccome non voglio fare le cose senza saperle motivare vorrei chiedere alcune delucidazioni.
    1) Perchè Ho dovuto usare una lista obbligatoriamente? cioè in un primo momento avevo provato a utilizzare un ArrayList (ovviamente di stringhe) ma il programma non funzionava...

    2) No mi è ben chiaro l'utilizzo di HashSet. Vorrei capire che ruolo ha in questo programma.

    3) Collections.frequency passa ogni singolo carattere di una determinata lista e restituisce un int corrispondente a quante volte si sia ripetuto il carattere corrispondente a s(in questo caso) giusto?

    4) Vorrei capire meglio il significato dei due punti. Mi è stato sempre detto che se inseriti nel for passano a ogni ciclo un carattere di una determinata stringa.
  • Re: Dubbio in merito a calcolo occorrenze

    ....
    Sono riuscito a realizzare questo codice che funziona. Solo che siccome non voglio fare le cose senza saperle motivare
    ...
    In effetti non sembrerebbe ti sia molto chiaro come funziona;

    prova a rileggere il tuo codice dopo aver rinominato le tue variabili così:

    tt2 => listaCaratteriInParolaTest

    parole => listaCaratteriUniciInParolaTest

    HTH
  • Re: Dubbio in merito a calcolo occorrenze

    sspintux ha scritto:


    ....
    Sono riuscito a realizzare questo codice che funziona. Solo che siccome non voglio fare le cose senza saperle motivare
    ...
    In effetti non sembrerebbe ti sia molto chiaro come funziona;

    prova a rileggere il tuo codice dopo aver rinominato le tue variabili così:

    tt2 => listaCaratteriInParolaTest

    parole => listaCaratteriUniciInParolaTest

    HTH
    Quindi in parole povere l'hashset serve a dividere la parola in singoli caratteri?
  • Re: Dubbio in merito a calcolo occorrenze

    Anonimamente22 ha scritto:


    Quindi in parole povere l'hashset serve a dividere la parola in singoli caratteri?
    No,
    nel tuo caso non permette ( leggi scarta se già presente) occorrenze ripetute di caratteri;

    in altre parole
    data la tua parolaTest="aa bb c"

    listaCaratteriInParolaTest contiene i seguenti elementi
    a
    a

    b
    b

    c

    listaCaratteriUniciInParolaTest contiene solo questi
    a

    b
    c

    Leggi la sua documentazione
  • Re: Dubbio in merito a calcolo occorrenze

    sspintux ha scritto:


    Anonimamente22 ha scritto:


    Quindi in parole povere l'hashset serve a dividere la parola in singoli caratteri?
    No,
    nel tuo caso non permette ( leggi scarta se già presente) occorrenze ripetute di caratteri;

    in altre parole
    data la tua parolaTest="aa bb c"

    listaCaratteriInParolaTest contiene i seguenti elementi
    a
    a

    b
    b

    c

    listaCaratteriUniciInParolaTest contiene solo questi
    a

    b
    c

    Leggi la sua documentazione
    In altre parole elimina i duplicati ammettendo un singolo carattere di quelli uguali giusto?
  • Re: Dubbio in merito a calcolo occorrenze

    Nella codifica ASCII ogni carattere è rappresentato da un Byte. Questo byte è sostanzialmente un numero, solo che quando il suo tipo viene definito come "char", viene tradotto come un carattere. Il processo inverso è lo stesso. Posso partire da un carattere ASCII e ricavarne la sua codifica come byte, cioè come numero. Se cerchi "tabella ASCII" su google puoi trovare come sono codificati i caratteri. Quindi, quando il compilatore si trova davanti qualcosa come:
     int[] count = new int['z' - 'a' + 1]; 
    'z' - 'a' + 1 deve quindi esser tradotto a numero.
    la codifica di 'z' (e solo di 'z' minuscola) è 122
    la codifica di 'a' è 97
    quindi l'operazione diventa:
    122 - 97 + 1 = 26
    e alla fine dei conti:
     int[] count = new int[26]; 
    niente di più, niente di meno.
Devi accedere o registrarti per scrivere nel forum
11 risposte