Iterowanie for-em własnej kolekcji

0

Jak już wcześniej pisałem nadrabiam zaległości z programowania , dziś mam właściwie bardzo podobny problem jak ostatnio( Ale to nie istotne bo i tak temat pewnie przez ogromną większość forum jest kompletnie nie znany )

Najpierw wkleję treść ćwiczenia udostępnionego przez mojego wykładowcę: A później zadam pytanie dotyczące go

Zdefiniować klasę Incrementor w taki sposób, aby następujący kod:

ackage incr;
import static incr.Incrementer.*;

public class Test {
  
  public static void main(String[] args) {
    
    // najprostsza iteracja - krok = 1
    for(int k : in(1, 10)) System.out.print(k + " ");
    System.out.println();
    
    // Podany krok
    for(int k : in(1, 10).by(2)) System.out.print(k + " ");
    System.out.println();
    
    // Można w odwrotną stronę - tu domyślnie krok = -1
    for(int k : in(10, 1)) System.out.print(k + " ");
    System.out.println();

    // Ale można zakres formułować od min do max, a podany krok będzie 
    // decydował o kierunku iteracji
    for(int k : in(1, 10).by(-1)) System.out.print(k + " ");
    System.out.println();
    
    // W trakcie iteracji można zmieniac krok
    Incrementer inc;
    for (int i : inc = in(1,10) ) {
      if (i == 4) inc.by(2);
      System.out.print(i + " ");
    }
    System.out.println();
    for (int i : inc = in(1,10) ) {
      if (i == 8) inc.by(-2);
      System.out.print(i + " ");
    }
    System.out.println();
    for(int k : inc = in(10, 1)) {
      if (k == 5) inc.by(1);
      System.out.print(k + " ");
    }

  }

}
dał w  wyniku:
1 2 3 4 5 6 7 8 9 10 
1 3 5 7 9 
10 9 8 7 6 5 4 3 2 1 
10 9 8 7 6 5 4 3 2 1 
1 2 3 4 6 8 10 
1 2 3 4 5 6 7 8 6 4 2 
10 9 8 7 6 5 6 7 8 9 10


Wymaganie:
w programie (w tym w klasie Incrementer) nie wolno stosować taablic ani kolekcji.

Podpowiedzi:
in(...) i by(...) są metodami w klasie Incrementer
Incrementer winien implementować interfejs Iterable

Pierwszy problem: to metoda in() która według mnie powinna znajdować się w clasie Test a dopiero wtedy z niej będę mógł się odwołać do metody z klasy Incrementator, prawda? bo w tej postaci która jest przedstawiona ,klasa test nie może wywołać metody in() z klasy Incrementator nawet gdyby była static.

Dwa: no więc zaimplementowałem interfejs Iterable dla Incrementer i interfejs iterator dla klasy Iteratora. Wszystko super, ale. Przyjąłem że in() zwraca mi obiekt Incrementer( widać w kodzie że metoda ta zwraca właśnie obiekt typu Incrementer) i zwraca obiekty typu Incrementer więc gdy już w pierwszym wywołaniu in() obiekty te są przypisywane do int k ja nie rozumiem jak.

Pozdrawiam i szczerze dziękuje każdemu komu będzie się chciało pomyśleć nad wytłumaczeniem mi tego.

0

Metoda in(...) powinna (tzn powinna, aby ten kod się skompilował) być statyczna i umieszczona w klasie Incrementer. Masz podany statyczny import z klasy Incrementer. Metoda by(...) powinna być oczywiście niestatyczna.

0

in() powinna być statyczna i powinna zwracać Incrementer o podanych parametrach...
coś w rodzaju:

public static Incrementer in(int n, int m)
{
   return new Incrementer(n, m);
}
0

Ale , jak to możliwe że do zmiennej int k : jest przypisywany Incrementator?

    // najprostsza iteracja - krok = 1
    for(int k : in(1, 10)) System.out.print(k 
+ " ");
    System.out.println();

nie ma przecież czegoś takiego jak funkcji toInt()

0

Ale tu chodzi o iterowaniu po elementach. int to typ elementu wypluwany przez Iterator. W sumie intem sparametryzować się nie da, więc trzeba implementować Iterable<Integer>. Potem powinien zadziałać autoboxing i rozpakować Integery do intów przy przeglądaniu.

Jak robisz
Iterable<Integer> iterableInteger = new ArrayList<Integer>();
iterableInteger.add(...);
for (Integer wartość : iterableInteger) {
...
}
To też nie ma tu metody w ArrayList typu toInt().

0

Skoro Incrementator implementuje Iterable to kompilator już sobie odpowiednio zamieni zapis for'a na odpowiedni zapis z użyciem iteratora.

Generalnie w pętli for(each) wymagane jest podanie klasy implementującej Iterable. I tyle.

0

No więc tak incrementer paramtryzuje tak:

public class Incrementer<T> implements Iterable< Incrementer<T> >{

A jak mam sparametryzować funkcje iterator??

	@Override
	public incrementerIterator<Incrementer<T>> iterator() {
		// TODO Auto-generated method stub
		return   new incrementerIterator<Incrementer<T>>(this);
	}

No i na końcu jak sparametryzować :

public class incrementerIterator<T> implements Iterator<T> {

Funkcja in wygląda tak:

public static Incrementer<Integer> in(int i, int j) {
		Incrementer<Integer> inc = new Incrementer<Integer>(i,j);
		return inc;
	}

Ja zdaje sobie sprawe że pytam o bardzo szczegółową odpowiedź , ale gdy taki przykład zrozumiem to będę wiedział jak posługiwać się parametrami typu na przyszłość. Trudno jest mi to pchnąć a zależy mi by się tego nauczyć.

Wszytskim dziękuje za dotychczasową pomoc w nauce.

0

Dla ciekawych rozwiązania:

Klasa Incremeter:

package incr;

import java.util.Iterator;

public class Incrementer implements Iterable<Integer> {
	
	int first;
	int second;
	int krok = 0;

	public Incrementer(int i, int j) {		
	first = i;
	second = j;
	}
	
	public  static Incrementer in(int i, int j) {
		Incrementer inc = new Incrementer(i,j);
		return inc;
	}
	
	
	public String toString(){
		return ""+ this.first;
		
	}

	@Override
	public Iterator<Integer> iterator() {
		// TODO Auto-generated method stub
		return   new incrementerIterator(this);
	}

	public Incrementer by(int i) {
		// TODO Auto-generated method stub
		krok = i;
		return this;
	}


	
	
}

Klasa IncrementerIterator

package incr;

import java.util.Iterator;

public class incrementerIterator implements Iterator<Integer> {

	
	int start;
	int end;
	Incrementer i ;
	
	
	public incrementerIterator(Incrementer incr) {
		i = incr;
		
		if(i.krok != 0 ){}
		else{
			if(incr.first > incr.second){i.krok = -1; }
			else{ i.krok = 1;}
		}
		
		if(i.krok > 0){
			if(incr.first > incr.second){
				start = incr.second  - i.krok ; end = incr.first;
			}
			else{
				start = incr.first - i.krok ; end = incr.second;
			}
		}
		else{
			if(incr.first > incr.second){
				start = incr.first - i.krok ; end = incr.second;
			}
			else{
				start = incr.second - i.krok ; end = incr.first;
			}	
		}
		
	}
	@Override
	public boolean hasNext() {
      if(i.krok>0){
    	  
    	  if(i.first > i.second){
			   end = i.first;
		  }
		  else{
		       end = i.second;
		  } 
    	  
    	  if( (start + i.krok) > end){
    		  return false;
    	  }
    	  else{
    		  return true;
    	  }
      }
      else{
    	  
    	  if(i.first > i.second){
		    	 end = i.second;
		  }
		  else{
		         end = i.first;
		  }	
    	  
    	  if( (start + i.krok) < end ){
    		  return false;
    	  }
    	  else{
    		  return true;
    	  }
      }
		
	}
	@Override
	public Integer next() {
		start =  start + i.krok;
		return start ;
		
	}
	@Override
	public void remove() {
		// TODO Auto-generated method stub
		
	}
	

	

}

1

Ale żeś nakombinował... przeanalizuj sobie to:

package incr;

import java.util.Iterator;

public class Incrementer implements Iterator<Integer>, Iterable<Integer>{

	public static Incrementer in(int i, int j)
	{
		return new Incrementer(Math.min(i, j), Math.max(i, j), i<j? 1 : -1);
	}
	
	int min;
	int max;
	int step;
	
	int current;
	
	public Incrementer(int min, int max, int step)
	{
		if(min>max)
			throw new IllegalArgumentException("min > max");
		this.min = min;
		this.max = max;
		
		current = min-1;// żeby metoda by się tym zajęła
		
		by(step);
	}
	
	public Incrementer by(int step)
	{
		if(step==0)
			throw new IllegalArgumentException("step must be != 0");
		
		// jeśli jesteśmy poza zakresem, to zaczynamy od nowa
		if(!contains(current))
			current = (step>0 ? min : max) - step;
		
		this.step = step;
		
		return this;
	}

	@Override
	public boolean hasNext()
	{
		return contains(current+step);
	}

	@Override
	public Integer next()
	{
		return current+=step;
	}

	@Override
	public void remove()
	{
		throw new UnsupportedOperationException("cannot remove from range");
	}
	
	public boolean contains(int i)
	{
		return i>=min && i<=max;
	}
	
	@Override
	public Iterator<Integer> iterator()
	{
		return this;
	}
}

Nie robiłem oddzielnego iteratora ze względu na to, że i tak nie byłby nigdzie trzymany jego stan... (current zmienia się z metody by, więc to byłoby bez sensu)

0

Odświeżam nieco temat, ponieważ mam parę pytań do tego programu. Akurat poznaję interfejsy dlatego to zadanie mnie zaciekawiło i przy czytaniu rozwiązań tutaj pojawił się problem.

W poleceniu jest:
Wymaganie:
w programie (w tym w klasie Incrementer) nie wolno stosować tablic ani kolekcji.

Podpowiedzi:
in(...) i by(...) są metodami w klasie Incrementer
Incrementer winien implementować interfejs Iterable

Co do tablic to wiadomo, ale z kolekcjami nie bardzo rozumiem. Wiem, że "Iterator umożliwia iterowanie po kolekcjach." Także występują tu kolekcje, których nie można stosować według polecenia?

'Incrementer winien implementować interfejs Iterable'
Więc w kodzie wymagane jest umieszczenie czegoś takiego:

public interface Iterable<Integer> {
  public Iterator<Integer> iterator();    
} 

?

0

Chodzi zapewne o napisanie klasy, która poza tym, że implementuje Iterable to jednocześnie dostarcza w pełni samodzielnej implementacji listy wiązanej. W efekcie "pod spodem" należy też zaimplementować odpowiedni iterator, który będzie wstanie chodzić po naszej implementacji listy.

0

A jak wygląda sprawa z interfejsem? Nie musi być podany w programie kod jaki dałam w poście? Czy wystarcza po prostu pisać

 class Incrementer implements Iterable<Integer> 

?
Bo nie wiem czy jeśli bym wspomniany interfejs tam dodała to by było tylko niepotrzebne wydłużanie kodu czy coś by to zmieniło.

0

Wystarczy napisać to co napisałaś. Tyle tylko, że trzeba napisać implementację metody iterator oraz samą implementację Iterator

0
 interface Iterable<Integer> {  
   Iterator<Integer> iterator();  
   } 

Wkleiłam taki kod.
O ile wczoraj wieczorem program działał, to nie jestem pewna co w nim zepsułam, bo dziś wyrzuca błędy np:

error: for-each not applicable to expression type  
for(int k : in(1, 10)) System.out.print(k + " ");
                 ^
  required: array or java.lang.Iterable
  found:    Incrementer

 error: for-each not applicable to expression type
    for(int k : in(1, 10).by(2)) System.out.print(k + " ");
                                   ^
  required: array or java.lang.Iterable
  found:    Incrementer

Analizuję klasy wstawione przez Microba także nie wstawiam kodu jeszcze raz.
Po prostu staram się przeanalizować kod i zrozumieć jak działa.

0

A pokaż swój kod...

0

http://wklej.org/id/1328476/

Chciałam sprawdzić jak działa ten program podany na poprzedniej stronie tego tematu i rozwiać wątpliwości jak wstawić tam interfejs oraz jak to właściwie jest z kolekcjami.
No i program wyrzuca błędy niestety i nie wiem czy to ja zepsułam kod czy to wina dodawania interfejsu może.

0

Keraj przecież wrzucił poprawny kod, bo ten autora jest zły.

0

Spróbowałam uruchomić kod Keraia, ale kompilator wyrzucił identyczne błędy.
Czy to może być wina programu? (używam JCreatora)

0

No to rzeczywiście zagadka, bo kod spełnia SOA#1 - u mnie działa. Możliwe, że masz coś z konfiguracją JCreatora... chociaż... sprawdź jeszcze:

for(int k : Incrementer.in(1, 10).by(2)){
            System.out.println(k);
        }
0

Dziwne, bo wciąż jest ten sam błąd. Nawet napisałam inny kod, to znaczy od początku, na swój sposób (nie wiem czy jest dobry, bo nie da się skompilować) i znów pokazuje identyczny problem.

0

Próbowałam przerobić jeszcze te kody jak i poprawiać swój. Nie wiem jak to zmienić i być może to jednak wina JCreatora :( jeśli tak, to czy da się to poprawić? W ustawieniach programu może?

Dokładna lista błędów:

 
 error: for-each not applicable to expression type
    for(int k : in(1, 10)) System.out.print(k + " ");
                  ^
  required: array or java.lang.Iterable
  found:    Incrementer

error: for-each not applicable to expression type
    for(int k : in(1, 10).by(2)) System.out.print(k + " ");
                            ^
  required: array or java.lang.Iterable
  found:    Incrementer

 error: for-each not applicable to expression type
    for(int k : in(10, 1)) System.out.print(k + " ");
                  ^
  required: array or java.lang.Iterable
  found:    Incrementer

error: for-each not applicable to expression type
    for(int k : in(1, 10).by(-1)) System.out.print(k + " ");
                            ^
  required: array or java.lang.Iterable
  found:    Incrementer

 error: for-each not applicable to expression type
    for (int i : inc = in(1,10) ) {
                     ^
  required: array or java.lang.Iterable
  found:    Incrementer

error: for-each not applicable to expression type
    for (int i : inc = in(1,10) ) {
                     ^
  required: array or java.lang.Iterable
  found:    Incrementer

 error: for-each not applicable to expression type
    for(int k : inc = in(10, 1)) {
                    ^
  required: array or java.lang.Iterable
  found:    Incrementer

7 errors
Process completed.

0
interface Iterable<Integer> {
  
   Iterator<Integer> iterator();
    
} 

Dodałeś interfejs incr.Iterable, zamiast użyć java.util.Iterable

0
 error: cannot find symbol
   Iterator<Integer> iterator();
   ^
  symbol:   class Iterator
  location: interface Iterable<Integer>
  where Integer is a type-variable:
    Integer extends Object declared in interface Iterable
 

Jeśli dodam kod, który podałeś to pojawia się taki błąd.

Wcześniejsza wersja http://wklej.org/id/1330153/
Dodanie interfejsu http://wklej.org/id/1330562/
Już tyle edytuje ten kod (jak i próbowałam uruchomić tamte na pierwszej stronie tego tematu), że naprawdę nie wiem co zrobić i chyba tylko namnożyło się błędów przez ciągłe zmiany.

Nie wiem czy to jest możliwe uruchomić ten program w JCreatorze w jednym pliku...

0

Pobrałam sobie NetBeans, już program działa właściwie.
Widać to była jednak wina JCreatora.
Tak czy inaczej dziękuję za chęć pomocy :)

1 użytkowników online, w tym zalogowanych: 0, gości: 1