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();    
} 

?

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