Iterator, nie działający w kolekcji, to generator?

0

Jak chce działać na jakimś zbiorze liczb przechodząc po nich iteratorem(a właściwie żeby iterator na nie działał, filtrując je), nie wrzucając ich w żadną kolekcje, to musze użyć generatora, czy jest inna możliwość?
Wyjaśnie na przykładzie ;p
Mam zbiór cyfr od 1 do 10 i robie
1 - > sprawdzam, jeśli true to wyświetlam, jeśli false to dalej
2 - > sprawdzam, jeśli true to wyświetlam, jeśli false to dalej
itd.

Podejrzewam że problem prosty, jednak nie mam pomysłu jak się zabrać.

0

Jak chce działać na jakimś zbiorze liczb przechodząc po nich iteratorem (...) to musze użyć generatora, czy jest inna możliwość?

Możesz użyć dowolnego rozwiązania, które ci pasuje.

No chyba, że chodziło ci o coś, co można wrzucić w for-eacha. For-each w Javie wymaga:

  • albo tablicy,
  • albo Iterable<Typ>,

Np tu masz prosty generator:

import java.util.Iterator;

class Range implements Iterable<Integer> {
    final int start, end;
    
    private Range(int start, int end) {
        this.start = start;
        this.end = end;
    }
    
    public static Range range(int start, int end) {
        if (start <= end) {
            return new Range(start, end);
        }
        throw new IllegalArgumentException();
    }

    @Override
    public Iterator<Integer> iterator() {
        return new Iterator<Integer>() {
            int current = start;

            @Override
            public boolean hasNext() {
                return current < end;
            }

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

            @Override
            public void remove() {
                throw new UnsupportedOperationException();
            }
        };
    }
}

public class Main {

    public static void main(final String[] args) throws Exception {
        for (int i : Range.range(0, 10)) {
            System.out.println(i);
        }
    }
}
0
Wibowit napisał(a):

Jak chce działać na jakimś zbiorze liczb przechodząc po nich iteratorem (...) to musze użyć generatora, czy jest inna możliwość?

Możesz użyć dowolnego rozwiązania, które ci pasuje.

No chyba, że chodziło ci o coś, co można wrzucić w for-eacha. For-each w Javie wymaga:

  • albo tablicy,
  • albo Iterable<Typ>,

Chodzi mi o to, że prosze użytkownika o podanie jakiejś liczby i algorytm, iteracyjnie ma wypisać liczby pierwsze MNIEJSZE od tej wartości, ale proces generowanie liczby do wypisania, ma działać na bieżąco przy odczycie przez iterator tej liczby(mam nadzieje że nie zamieszałem). Nie mogę używać tablic/kolekcji/co tam jeszcze jest. Zakładam że muszę utworzyć iterator filtrujący, oraz iterator odwrotny(zeby leciał z góry do dołu). No i tutaj rodzi się problem, bo iterator z definicji, musi działać na kolekcjach/tablicy. Jego zamiennikiem w sytuacji bez kolekcji, jest generator, lecz nie udało mi się nic sprawnego napisać ;)

Teraz nieco bardziej nakreśliłem problem, bo niestety Twój generator troszeczkę kłóci się z moimi założeniami ;) Z góry dzięki za pomoc

0

Eee tam, własnie że się nie kłóci.

Gotowiec:

import java.util.Iterator;

class PrimalityTester {

    static boolean isPrime(int x) {
        if (x < 2) {
            return false;
        } else {
            for (int a = 2; a * a <= x; a++) {
                if (x % a == 0) {
                    return false;
                }
            }
            return true;
        }
    }
}

enum HasNextState {

    NotComputed, NoNext, HasNext
}

class PrimesFilter implements Iterable<Integer> {

    final Range range;

    public PrimesFilter(Range range) {
        this.range = range;
    }

    @Override
    public Iterator<Integer> iterator() {
        return new Iterator<Integer>() {
            HasNextState state = HasNextState.NotComputed;
            Integer next = null;
            Iterator<Integer> underlyingIterator = range.iterator();

            @Override
            public boolean hasNext() {
                if (state == HasNextState.NotComputed) {
                    state = HasNextState.NoNext;
                    while (underlyingIterator.hasNext()) {
                        Integer toCheck = underlyingIterator.next();
                        if (PrimalityTester.isPrime(toCheck)) {
                            next = toCheck;
                            state = HasNextState.HasNext;
                            break;
                        }
                    }
                }
                return state == HasNextState.HasNext;
            }

            @Override
            public Integer next() {
                if (state == HasNextState.NoNext) {
                    throw new IndexOutOfBoundsException();
                }
                if (state == HasNextState.NotComputed) {
                    hasNext();
                }
                state = HasNextState.NotComputed;
                return next;
            }

            @Override
            public void remove() {
                throw new UnsupportedOperationException();
            }
        };
    }
}

class Range implements Iterable<Integer> {

    final int start, end;

    private Range(int start, int end) {
        this.start = start;
        this.end = end;
    }

    public static Range range(int start, int end) {
        if (start <= end) {
            return new Range(start, end);
        }
        throw new IllegalArgumentException();
    }

    @Override
    public Iterator<Integer> iterator() {
        return new Iterator<Integer>() {
            int current = start;

            @Override
            public boolean hasNext() {
                return current < end;
            }

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

            @Override
            public void remove() {
                throw new UnsupportedOperationException();
            }
        };
    }
}

public class Main {

    public static void main(final String[] args) throws Exception {
        for (int i : new PrimesFilter(Range.range(0, 40))) {
            System.out.println(i);
        }
    }
}

PS:
Pisane na szybko, więc być może niepotrzebnie zamotane.

0

Witam ponownie!
Cały weekend starałem się ogarnąć klasę filtrującą, ale nadal mam problem(nie jestem bardzo zaawansowany w javie, kompletnie olałem podstawy i teraz na kolejnym semestrze ponoszę tego odpowiedzialność) ;)
Mianowicie:

enum HasNextState {
    NotComputed, NoNext, HasNext
}
 
class FiltrPierwszej implements Iterable<Integer> {
 
    final IteratorPrzechodzacy range;
 
    public FiltrPierwszej(IteratorPrzechodzacy range) {
        this.range = range;
    }
 
    public Iterator<Integer> iterator() {
        return new Iterator<Integer>() {
            HasNextState state = HasNextState.NotComputed;
            Integer next = null;
            Iterator<Integer> underlyingIterator = range.iterator();
 
            public boolean hasNext() {
                if (state == HasNextState.NotComputed) 
                {
                    state = HasNextState.NoNext;
                    while (underlyingIterator.hasNext()) 
                    {
                        Integer toCheck = underlyingIterator.next();
                        if (Warunek.isPrime(toCheck)) 
                        {
                            next = toCheck;
                            state = HasNextState.HasNext;
                            break;
                        }
                    }
                }
                return state == HasNextState.HasNext;
            }
 
            public Integer next() {
                if (state == HasNextState.NoNext) {
                    throw new IndexOutOfBoundsException();
                }
                if (state == HasNextState.NotComputed) {
                    hasNext();
                }
                state = HasNextState.NotComputed;
                return next;
            }
 
            public void remove() {
                throw new UnsupportedOperationException();
            }
        };
    }
}

Czy mógłbyś mi trochę opisać tą klasę. Dokładnie chodzi mi o metodę hasNext() - bo zakladam ze jest ona sprawdzającą, czy następny element jest liczbą pierwszą.

Rzecz jasna program działa i bardzo za niego dziękuje, ale java zaczyna mi się podobać i chciałbym trochę zgłebić wiedzę na temat iteratorów, bo wydają się być straszne zagmatwane.

Sam starałem się zrobić całość na generatorze, generatorze filtrującym(do którego byłby dołączony predykat w postaci sprawdzana czy następny element jest akceptowalny). Jednak taki zamieszany program, wywalał mi wiecznie błąd odnoszący się do niekompatybilności typu gdy próbowałem utworzyć obiekt klasy Generator, ktory były obiektem Generatora filtrujacego o parametrach(generator, predykat).

Wiem że zamieszane, ale ja zazwyczaj robie programy na około ;)

0

Są dwa różne interfejsy:

  • Iterator służący do jednokrotnego przeiterowania (nie da się go zresetować),
  • Iterable, które zwraca za każdym razem nowy iterator (a więc dzięki temu można iterować wiele razy),

Iterator ma trzy metody:

  • hasNext,
  • next,
  • remove
    Remove się tutaj nie zajmujemy, ale i tak funkcjonalność dość ograniczona (ale w zupełności wystarczająca do efektywengo iterowania).

W moim PrimesFilter:

  • przy zwracaniu nowego iteratora najpierw pobieram nowy iterator z Iterable pod spodem,
  • przy iterowaniu muszę w jakiś sposób obliczyć naprzód czy jakieś elementy mi zostały,
  • to obliczanie robię w metodzie hasNext,
  • metoda next ma zrócić następny element i go zwraca, ale wyszukiwanie następnego elementu deleguje do metody hasNext, bo nie ma sensu powielać kodu w dwóch funkcjach,
  • w zasadzie kod jest skomplikowany głównie dlatego, że w interfejsie Iterator nie ma takiej funkcji jak current() która zwracałaby aktualny element i nie przechodziła do następnego - metoda next() zawsze przechodzi do następnego elementu i dlatego muszę sobie sam zaemulować funkcjonalność tej hipotetycznej funkcji current(),

Sam starałem się zrobić całość na generatorze, generatorze filtrującym(do którego byłby dołączony predykat w postaci sprawdzana czy następny element jest akceptowalny). Jednak taki zamieszany program, wywalał mi wiecznie błąd odnoszący się do niekompatybilności typu gdy próbowałem utworzyć obiekt klasy Generator, ktory były obiektem Generatora filtrujacego o parametrach(generator, predykat).

Pokaż kod.

PS:
Zamiast:

    final Range range;
 
    public PrimesFilter(Range range) {
        this.range = range;
    }

powinno być w sumie:

    final Iterable<Integer> underlyingIterable;
 
    public PrimesFilter(Iterable<Integer> underlyingIterable) {
        this.underlyingIterable = underlyingIterable;
    }

ponieważ wcale nie potrzeba pod spodem konkretnie Range, a wystarczy Iterable<Integer>.

Interfejs Collection rozszerza Iterable, więc wszystko co jest Collection można też wrzucić jako parametr do konstruktora.

0

Ok, w takim razie mniej więcej wszystko ogarniam, ale i tak proszę o sprawdzenie mojego kodu:

import Iteratory.*;
import java.io.*;
import java.util.Scanner;

public class Lab2_2
{   
    int stala;
    ReverseGenerator gen;
    ReverseGenerator filtr = new ReverseFilterIterator(gen, new PrimePredicate());
    
    public Lab2_2(int n)
    {
       this.stala = n;
    }
 }

public class PrimePredicate implements Predicate2 {

    public boolean accept(Object ob)
    {
        Integer i = (Integer) ob;
        return isPrime(i.intValue());
    }
        
    private boolean isPrime(int n)
    {
        if(n<2) return false;
        if(n == 2) return true;
        else
            if(n%2 == 0) return false;
                else
                {
                    boolean isPrime= true;
                    int x =3;
                    while(isPrime && x <= Math.sqrt(n))
                    {
                        if(n%x == 0)
                            isPrime = false;
                        else
                            x+=2;
                     }
                     return isPrime;
                    }
        }

    }

public class ReverseGenerator implements Iterator {

    int _n;
    int current;

    public ReverseGenerator(int n){
        _n=n;
        current = n;
    }

    public boolean hasNext() {
        return (current>1);
    }

    public void last(){
        current=_n;
    }
    
    public Object next() {
        --current;
        return current;
    }
        
    public int current() {
        return current;
    }
    
    public void remove() {

    }
}

public class ReverseFilterIterator
{   private ReverseGenerator gen;
    private Predicate2 pred;

    public ReverseFilterIterator(ReverseGenerator gen, Predicate2 pred)
    {  
        this.gen=gen; 
        this.pred=pred; 
    }  
  
    public void filterBackwards()
    { 
        while( !gen.hasNext() && !pred.accept(gen.current()))
        gen.next();
    }
   
    public void last()
    { 
      gen.last(); 
      filterBackwards();
    }

    public void previous()
    {
      gen.next();
      filterBackwards();
    }
    
    public boolean hasNext()
    {
        return gen.hasNext(); 
    }
    
    public int current()
    { 
        return gen.current();
    }
}
0

Nie wiem co chciałeś osiągnąć. Podaj pełne wymagania problemu.

Dodałeś jakieś funkcje typu last(), current() itp itd których nie ma w interferjsie Iterator(). Twój kod nie będzie działał jako typowy Iterator, nie da się wrzucić twoich obiektów do for-eacha, nie da się ich złożyć z Iterable'ami typu chociażby List. W moim rozwiązaniu wszystko to się da, jest w 100% zgodne z Javową hierarchią i semantyką kolekcji. Javowe iteratory nie mają generalnie możliwości resetowania, natomiast twoje mają. To samo z metodą current().

0

Problem rozwiązany. Zebrałem się w sobie i napisałem jeszcze raz program od 0 i uprościłem go 100 razy i oczywiście działa ;) Za dużo kombinowałem. Bardzo dziękuje za odpowiedź Wibowit, ale sam zapomniałem o tym, że iterator musiałem sam napisać(tak jakby swój).
Oto kod jakby ktoś potrzebował.
Generator liczb pierwszych mniejszych od podanej N.

public class PrimeIterator
{
    int _last;
    int _current;

    private boolean isDone(){
        return _current<1 || _current>_last;
    }
    
    private void next(){
        _current--;
        while(_current>0 && !isPrime(_current)){
            _current--;
        }
    }
    
    private static boolean isPrime(long n) {
     boolean prime = true;
     for (long i = 3; i <= Math.sqrt(n); i += 2)
        if (n % i == 0) {
            prime = false;
            break;
        }
     if (( n%2 !=0 && prime && n > 2) || n == 2) {
           return true;
     } else {
        return false;
     }
    }
    
    public void PrimeIterator(int n)
    {
        this._last=n;
        this._current=n;
        next();
        while(!isDone())
        {
            System.out.println(_current);
            next();
        }
    }
}

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