Funzionamento iteratori

di il
57 risposte

57 Risposte - Pagina 3

  • Re: Funzionamento iteratori

    Paolinos ha scritto:


    Se Iterator viene parametrizzato in questo modo:
    
    public Iterator<Integer> iterator() {
       return new MyIter();
    }
    
    sarebbe corretto:
    
    private class MyIter implements Iterator {
    
    	public int next() { 
    		...
    	}
    	
    	...
    }
    
    No, sarebbe corretto

    private class MyIter implements Iterator<Integer> {

    e poi

    public Integer next()

    Paolinos ha scritto:


    L'interfaccia è corretta così:
    
    public interface Ins<T> extends Iterable<T>, Cloneable {
    	...
    	Iterator iterator();
    }
    
    Sarebbe corretto

    Iterator<T> iterator();
  • Re: Funzionamento iteratori

    Grazie per l'aiuto e la pazienza

    Adesso per poter utilizzare l'iteratore all'interno dei vari metodi della classe BoolSet, devo creare un oggetto Iterator per scorrere l'array in questo modo:
    
    Iterator<Integer> myIterator = this.new MyIter();
    
    Nel mio caso:
    
    public class BoolSet implements Ins<Integer> {
    	
    	private boolean[] arr;
    	
    	//metodo che controlla se l'insieme è vuoto
    	public boolean isEmpty() {
    		if(arr == null)
    			return true;
    		else
    			return false;
    	}
    	
    	//metodo che restituisce il massimo intero dell'insieme, -1 se l'insieme è vuoto
    	public class int massimo() {
    	
    		Iterator<Integer> myIterator = this.new MyIter();
    		int max = -1;
    		
    		if(isEmpty())
    			return max;
    			
    		while (myIterator.hasNext()) {
    			int temp_max;
    			temp_max =  myIterator.next();
    			if(temp_max > max)
    				max = temp_max;
    		}
    		
       		return max;
    	}
    
    	public Iterator<Integer> iterator() {
    		return new MyIter();
    	}
    	
    	private class MyIter implements Iterator<Integer> { 
             	// ...
    	}
    	
    	// ... altri metodi ...
    
    }
    
  • Re: Funzionamento iteratori

    Paolinos ha scritto:


    Adesso per poter utilizzare l'iteratore all'interno dei vari metodi della classe BoolSet, devo creare un oggetto Iterator per scorrere l'array in questo modo:
    A dire il vero, non è affatto detto che devi usare l'iteratore per fare altre operazioni interne al BoolSet (se non ti è stato richiesto esplicitamente di fare così).

    Tanto per dirne una: trovare il massimo. Si fa un ciclo lineare che parte dall'ultimo indice e va verso 0. Il primo true che trovi quello è il massimo. Niente iterator.

    P.S. sicuro che "empty" voglia dire che arr è null ?? Mi pare un po' limitato ..... e se ci fossero 10 boolean e sono tutti false? Non è anche questo "empty" ??
  • Re: Funzionamento iteratori

    Sul fatto che non devo utilizzare per forza l'iteratore sono d'accordo, volevo semplicemente capire se il suo utilizzo è corretto nel'esempio (tralasciando il discorso su isEmpty()):
    
    public class BoolSet implements Ins<Integer> {
       
       private boolean[] arr;
       
       //metodo che controlla se l'insieme è vuoto
       public boolean isEmpty() {
          if(arr == null)
             return true;
          else
             return false;
       }
       
       //metodo che restituisce il massimo intero dell'insieme, -1 se l'insieme è vuoto
       public class int massimo() {
       
          Iterator<Integer> myIterator = this.new MyIter();
          int max = -1;
          
          if(isEmpty())
             return max;
             
          while (myIterator.hasNext()) {
             int temp_max;
             temp_max =  myIterator.next();
             if(temp_max > max)
                max = temp_max;
          }
          
             return max;
       }
    
       public Iterator<Integer> iterator() {
          return new MyIter();
       }
       
       private class MyIter implements Iterator<Integer> { 
                // ...
       }
       
       // ... altri metodi ...
    
    }
    
    sicuro che "empty" voglia dire che arr è null ?? Mi pare un po' limitato ..... e se ci fossero 10 boolean e sono tutti false? Non è anche questo "empty" ??
    E' verissimo, ma avevo intenzione di utilizzare una variabile che conta il numero di elementi (=true) e che ponga a null l'array se tale valore arriva a 0. Si può considerare una buona scelta?
  • Re: Funzionamento iteratori

    Paolinos ha scritto:


    volevo semplicemente capire se il suo utilizzo è corretto nel'esempio
    Sì, il massimo() è funzionalmente/tecnicamente corretto. Puoi migliorare un pochino mettendo la creazione dell'iteratore solo dopo che hai testato che non è empty. Perché se empty hai creato l'iteratore per nulla.

    Nota che non serve il this in this.new MyIter(). Il this è già implicito (essendo in un metodo di istanza), quindi basta new MyIter()

    Paolinos ha scritto:


    E' verissimo, ma avevo intenzione di utilizzare una variabile che conta il numero di elementi (=true) e che ponga a null l'array se tale valore arriva a 0. Si può considerare una buona scelta?
    No, annullare (= null) l'array non mi pare una buona idea, se viene inserito un nuovo valore dovresti re-istanziare l'array.

    Tra l'altro una cosa che non hai detto fin dall'inizio: l'array deve essere istanziato di dimensione fissa alla costruzione del BoolSet o deve essere "espandibile" man mano che si aggiungono valori?

    E comunque non serve andare a "contare" gli elementi. Basta tenersi una variabile (di istanza) con il numero "logico" di elementi. Ad ogni aggiunta incrementi, ad ogni rimozione decrementi. E il "empty" è semplicemente se è 0.
  • Re: Funzionamento iteratori

    Tra l'altro una cosa che non hai detto fin dall'inizio: l'array deve essere istanziato di dimensione fissa alla costruzione del BoolSet o deve essere "espandibile" man mano che si aggiungono valori?
    L'array ha dimensioni massime limitate solo dalla memoria disponibile
    Quindi nella classe Test creo:
    
    Ins insieme1 = new BoolSet(); //a questo punto l'insieme è vuoto
    
    Per esempio se eseguo l'operazione put(1000), cioè inserisco l'intero 1000 nell'insieme, e il mio array al momento ha length=10 dovrò ridimensionarlo.
    E comunque non serve andare a "contare" gli elementi. Basta tenersi una variabile (di istanza) con il numero "logico" di elementi. Ad ogni aggiunta incrementi, ad ogni rimozione decrementi. E il "empty" è semplicemente se è 0.
    Ti riferisci al fatto che se per esempio arr=[ F F F T F F T F F ]
    conta=2

    Se rimuovo 3 e 6 allora conta=0 quindi:
    
    public class boolean isEmpty() {
    	if(conta==0)
    		return true;
    	else
    		return false;
    }			
    
    Più o meno era il mio pensiero scartando l'idea di porre a null l'array
  • Re: Funzionamento iteratori

    Paolinos ha scritto:


    Per esempio se eseguo l'operazione put(1000), cioè inserisco l'intero 1000 nell'insieme, e il mio array al momento ha length=10 dovrò ridimensionarlo.
    Sì, dovrai istanziarne uno nuovo di capacità sufficiente, ricopiare tutti i valori dal vecchio al nuovo e assegnare il nuovo array alla variabile, in modo che il vecchio venga "buttato" via (non essendo più raggiungibile finirà in pasto al garbage collector).
    Questo richiede un minimo di logica e va fatto non necessariamente sempre ma solo se vedi che non hai capacità sufficiente.

    Paolinos ha scritto:


    Ti riferisci al fatto che se per esempio arr=[ F F F T F F T F F ]
    conta=2
    Intendevo dire tenere una variabile di istanza con il numero "logico" di elementi es.

    private int logicalSize;

    Da tenere aggiornato ovviamente ad ogni modifica che sia.
  • Re: Funzionamento iteratori

    Sto riflettendo sull'operazione di intersezione, quindi l'implementazione di:
    public void inter(Ins k)
    richiamata nella classe Test:
    
    // ...
    Ins insieme1 = new BoolSet();
    insieme1.put(2); //inserisce l'intero 2 nell'ins
    insieme1.put(1);
    Ins insieme2 = new BoolSet();
    insieme2.put(3);
    insieme2.put(1);
    insieme2.put(4);
    insieme1_clone = (Ins) insieme1.clone(); //clona l'insieme1
    insieme1_clone.inter(insieme2);
    // ...
    
    Inizialmente:
    insieme1_clone = [ F T T ]
    insieme2 = [ F T F T T ]

    Un elemento appartiene all'intersezione se l'i-esimo elemento è true sia per l'array dell'insieme1_clone che per l'insieme2. Quindi nell'esempio sopra l'intersezione sarebbe composta dal solo elemento "1". insieme1_clone verrà modificato e conterrà solo l'elemento di indice 1 = true.
    insieme1_clone = [ F T F ]

    In questo caso non so se sia conveniente utilizzare un doppio iteratore:
    
    public void inter(Ins k) {		
    		int i=0;
    		Iterator<Integer> myIterator = new k.MyIter();
    		Iterator<Integer> myIterator2 = new MyIter();
    		while (myIterator.hasNext()) {
    	        if(myIterator.next() == myIterator2.next()) //verifica se hanno lo stesso indice
    		        arr[i]=true;
    				else
    					arr[i]=false;
    			i++;	
    	    }
    
    Mi viene il dubbio se posso avere dei problemi se la dimensione dell'array di insieme1_clone sia > di insieme2.
  • Re: Funzionamento iteratori

    Paolinos ha scritto:


    In questo caso non so se sia conveniente utilizzare un doppio iteratore:
    Quello che hai scritto comunque ho poco/niente senso. Non è comunque così, iterando in perfetto "parallelo", che si può fare.

    Se un insieme avesse: 3 7 8 9
    e l'altro insieme avesse: 3 8 9 10

    tu fai:
    3 == 3 ok, lo tengo a true
    7 == 8 no
    8 == 9 no
    9 == 10 no

    Ma 8 e 9 ci sono in entrambi!!!

    Bisogna RAGIONARE di più .....

    Inoltre hai usato == che con gli oggetti (hai degli Integer) non è appropriato.

    Paolinos ha scritto:


    		Iterator<Integer> myIterator = new k.MyIter();
    Non puoi usare new k.MyIter()
    Ins è una interfaccia nel tuo caso. E al metodo inter potrebbe essere passato un oggetto (che ovviamente deve implementare Ins) che NON è della tua classe BoolSet. Potrebbe essere qualunque altra implementazione di Ins. E quindi secondo te avrebbe senso?
    Se il metodo avesse come parametro BoolSet (la TUA implementazione che ha MyIter come inner-class), allora sì è lecito. Altrimenti no.

    E inoltre la sintassi corretta sarebbe: istanzaOuter.new ClasseInner()
  • Re: Funzionamento iteratori

    Ho modificato in questo modo:
    
    public class BoolSet implements Ins<Integer> {
    	
    	private boolean[] arr;
    	
    	// ...
    	
    	public void inter(Ins k) {
    		Iterator<Integer> myIterator = new MyIter();
    		while(myIterator.hasNext()) {
    	      int temp=myIterator.next(); //temp = il prossimo indice con true
    			if(k.contiene(temp)) //contiene() dice se l'indice appartiene all'insieme y
    				arr[temp]=true;
    			else
    				arr[temp]=false;	
    		}		
    	}
    	
    	public boolean contiene(int x) {
    		if(x >= arr.length) 
    			return false;
    		Iterator<Integer> myIterator = new MyIter();
    		while (myIterator.hasNext()) {
    	         if(myIterator.next() == x)
    	            return true;
    	    }
    		return false;
    	}	
    }	
    
  • Re: Funzionamento iteratori

    Contiene non ha senso che usi l'iteratore.

    arr[temp]=true; è superfluo. Se hai estratto quel valore, il suo rispettivo boolean è sicuramente già a true.

    public void inter(Ins k) sarebbe più corretto se fosse public void inter(Ins<Integer> k) altrimenti a inter si potrebbe passare un es. oggetto che implementa Ins<Double> che ovviamente non ha senso.
  • Re: Funzionamento iteratori

    
    public void inter(Ins<Integer> k) {
    	Iterator<Integer> myIterator = new MyIter();
    	while(myIterator.hasNext()) {
    	    int temp=myIterator.next(); //temp = il prossimo indice con true
    		 if(!k.contains(temp))
    			 arr[temp]=false;
    	 }		
    }
    
    public boolean contiene(int x) {
    	if(x >= arr.length) 
    		return false;
    	return(arr[x]);
    }
    
    
    Nell'interfaccia Ins:
    void inter(Ins<T> k);
    Ho implementato anche il metodo clona() (clona l'insieme) in questo modo:
    
    public BooleanSet clona() {
    	try {
    		return (BooleanSet) super.clone();
    	} catch (CloneNotSupportedException e) {
    		throw new RuntimeException(e);
    	}
    }
    
  • Re: Funzionamento iteratori

    Paolinos ha scritto:


    
    public void inter(Ins<Integer> k) {
    	Iterator<Integer> myIterator = new MyIter();
    	while(myIterator.hasNext()) {
    	    int temp=myIterator.next(); //temp = il prossimo indice con true
    		 if(!k.contains(temp))
    			 arr[temp]=false;
    	 }		
    }
    
    public boolean contiene(int x) {
    	if(x >= arr.length) 
    		return false;
    	return(arr[x]);
    }
    
    Molto meglio. Se proprio vogliamo fare i fini si dovrebbe anche controllare che x sia >= 0.

    Paolinos ha scritto:


    Nell'interfaccia Ins:
    void inter(Ins<T> k);
    E siccome tu hai "fissato" la parametrizzazione quando hai fatto BoolSet implements Ins<Integer> in sostanza vuol dire che la signature di cui fare l'override è appunto void inter(Ins<Integer>)

    Paolinos ha scritto:


    Ho implementato anche il metodo clona() (clona l'insieme) in questo modo:
    
    public BooleanSet clona() {
    	try {
    		return (BooleanSet) super.clone();
    	} catch (CloneNotSupportedException e) {
    		throw new RuntimeException(e);
    	}
    }
    
    No, non è sufficiente!
    Il tuo BoolSet estende implicitamente Object. Il clone() di Object si limita SOLO a copiare i valori dei campi pari pari dall'oggetto corrente a quello nuovo "clonato".
    Se un campo è primitivo, no prob. Se è un campo reference ad un oggetto "immutabile" (es. Integer, String), no prob. perché se anche il vecchio e il clonato condividono lo stesso riferimento, essendo l'oggetto immutabile non causa alcun problema.
    Ma il tuo boolean[] è mutabile! Quindi il BoolSet vecchio e il BoolSet clonato hanno il riferimento allo STESSO array e la modifica su un BoolSet si ripercuote e si "vede" anche dall'altro e viceversa.

    In pratica così hai solo fatto una "shallow" copy e non una "deep" copy. In questi casi devi fare qualcosa tu esplicitamente, ovvero CLONARE l'array (sì, gli array hanno il clone() e tra l'altro da Java 5 sfrutta il tipo di ritorno "covariante").

    Ultima considerazione: usare super.clone() non è sbagliato. In questo caso è meno importante/necessario. Serve sicuramente quando sei in una gerarchia più complessa e hai svariate classi "al di sopra" (e magari NON sotto il tuo controllo). In questo caso è importante chiamare il clone "di sopra" così da fare la cosa giusta, qualunque cosa faccia. Ma nel tuo caso SAI che estendi direttamente Object.

    Ah: clone() ... non clona()


    P.S. Ahhh se avessi una conoscenza solida e cristallina di Java come ce l'ho io ....
  • Re: Funzionamento iteratori

    In pratica così hai solo fatto una "shallow" copy e non una "deep" copy. In questi casi devi fare qualcosa tu esplicitamente, ovvero CLONARE l'array (sì, gli array hanno il clone() e tra l'altro da Java 5 sfrutta il tipo di ritorno "covariante").
    Se ho capito:
    
    public BoolSet clone() {
    	BoolSet ins_new = new BoolSet();
    	ins_new.arr=arr.clone(); //clono l'array
    	ins_new.count=count; //count var istanza	
    	return(ins_new);
    }
    
    nella classe Test viene richiamato con:
    
    Ins insieme1b = (Ins) insieme1.clone();
    
    Una domanda: clonare l'array con clone() e utilizzare System.arraycopy() è la stessa cosa?
  • Re: Funzionamento iteratori

    Paolinos ha scritto:


    
    public BoolSet clone() {
    	BoolSet ins_new = new BoolSet();
    	ins_new.arr=arr.clone(); //clono l'array
    	ins_new.count=count; //count var istanza	
    	return(ins_new);
    }
    
    Non è sbagliato ma si può fare un pelino meglio.

    Paolinos ha scritto:


    
    Ins insieme1b = (Ins) insieme1.clone();
    
    Il cast (Ins) è superfluo. clone ritorna un BoolSet che è-un Ins

    Paolinos ha scritto:


    Una domanda: clonare l'array con clone() e utilizzare System.arraycopy() è la stessa cosa?
    No, non proprio. System.arraycopy è generico per la copia tra due array e ne può copiare anche solo una parte. Inoltre arraycopy NON crea un bel niente, sposta (copia) solo dei dati.

    Il clone() invece è il metodo appropriato per la "clonazione". Negli array il clone() fa una "deep" copy SOLO nel caso particolare di array di primitivi a 1 dimensione. Per tutti gli altri tipi di array la copia è "shallow".
Devi accedere o registrarti per scrivere nel forum
57 risposte