Java'da kendi yineleyicimizi yazabilir miyiz?


104

İçeren bir listem varsa [alice, bob, abigail, charlie]ve 'a' ile başlayan öğeleri yineleyen bir yineleyici yazmak istersem, kendi listemi yazabilir miyim? Bunu nasıl yapabilirim ?


4
Yapabilirsin. Yineleyici arayüzünü uygulamanız gerekir.
gd1

elbette, bu sadece normal bir arayüz. JDO impl. İçin java.util proxy'si oldukça fazla özel yineleyici içerir.
bestsss

Yanıtlar:


48

Elbette. Yineleyici, java.util.Iteratorarayüzün yalnızca bir uygulamasıdır . Kaynaktan var olan bir yinelenebilir nesneyi (örneğin, a LinkedList) kullanıyorsanız java.util, ya kendi alt sınıfınızı iteratordöndürmek için ya da kendi özel Iteratorörneğinize standart bir yineleyici sarmak için bir yol sağlamanız gerekir ( daha geniş kullanım avantajına sahiptir) vb.


8
iyi cevap .... +1 Ancak LinkedList'i alt sınıfa koymak zorunda değilsiniz. Arayüzler yapıcılar hakkında hiçbir şey söylemediğinden, yeni CustomIterator (somelist) ile somutlaştırılmış bir CustomIterator yazabilirsiniz.
gd1

1
@Giacomo: "... veya özel Iteratorörneğinize standart bir yineleyici sarmanın bir yolunu sunun ..." derken bunu kastettim (ve teşekkürler). :-)
TJ Crowder

197

Yeniden kullanılabilir en iyi seçenek, yinelenebilir arabirimi uygulamak ve yöntem iteratörünü () geçersiz kılmaktır.

Iterator () yöntemini geçersiz kıldığınız, arabirimi uygulayan ArrayList benzeri bir sınıf örneğini burada bulabilirsiniz.

import java.util.Iterator;

public class SOList<Type> implements Iterable<Type> {

    private Type[] arrayList;
    private int currentSize;

    public SOList(Type[] newArray) {
        this.arrayList = newArray;
        this.currentSize = arrayList.length;
    }

    @Override
    public Iterator<Type> iterator() {
        Iterator<Type> it = new Iterator<Type>() {

            private int currentIndex = 0;

            @Override
            public boolean hasNext() {
                return currentIndex < currentSize && arrayList[currentIndex] != null;
            }

            @Override
            public Type next() {
                return arrayList[currentIndex++];
            }

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

Bu sınıf, Generics kullanarak yinelenebilir arabirimi uygular . Dizinin elemanlarına sahip olduğunuzu düşünürsek, örneğin "foreach" döngüsü tarafından kullanılan gerekli olan bir Yineleyici örneğini elde edebileceksiniz.

Genişletici Yineleyici oluşturmadan yineleyicinin anonim bir örneğini oluşturabilir ve dizi üzerinde nereye gidebileceğinizi doğrulamak için currentSize değerinden yararlanabilirsiniz (diyelim ki 10 kapasiteli bir dizi oluşturdunuz, ancak yalnızca 2 0 ve 1'deki öğeler). Örnek, bulunduğu yerin sahip sayacına sahip olacak ve yapmanız gereken tek şey, geçerli değerin boş olup olmadığını doğrulayan hasNext () ile oynamak ve next (), bu da currentIndex'inizin örneğini döndürecektir. Aşağıda bu API'yi kullanmanın bir örneği var ...

public static void main(String[] args) {
    // create an array of type Integer
    Integer[] numbers = new Integer[]{1, 2, 3, 4, 5};

    // create your list and hold the values.
    SOList<Integer> stackOverflowList = new SOList<Integer>(numbers);

    // Since our class SOList is an instance of Iterable, then we can use it on a foreach loop
    for(Integer num : stackOverflowList) {
        System.out.print(num);
    }

    // creating an array of Strings
    String[] languages = new String[]{"C", "C++", "Java", "Python", "Scala"};

    // create your list and hold the values using the same list implementation.
    SOList<String> languagesList = new SOList<String>(languages);

    System.out.println("");
    // Since our class SOList is an instance of Iterable, then we can use it on a foreach loop
    for(String lang : languagesList) {
        System.out.println(lang);
    }
}
// will print "12345
//C
//C++
//Java
//Python
//Scala

İsterseniz, Iterator örneğini kullanarak da yineleyebilirsiniz:

// navigating the iterator
while (allNumbers.hasNext()) {
    Integer value = allNumbers.next();
    if (allNumbers.hasNext()) {
        System.out.print(value + ", ");
    } else {
        System.out.print(value);
    }
} 
// will print 1, 2, 3, 4, 5

Foreach belgeleri http://download.oracle.com/javase/1,5.0/docs/guide/language/foreach.html adresinde bulunmaktadır . Kişisel pratiğim google kodunda daha eksiksiz bir uygulamaya göz atabilirsiniz .

Şimdi, ihtiyacınız olanın etkilerini elde etmek için Yineleyiciye bir filtre kavramı eklemeniz gerektiğini düşünüyorum ... Yineleyici sonraki değerlere bağlı olduğundan, hasNext () 'de true döndürmek zor olacak ve sonra sonraki () gerçeklemeyi bir char "a" ile başlamayan bir değerle filtreleyin örneğin. Verilen filtreye sahip değerlere sahip filtrelenmiş bir listeye dayalı ikincil bir Interator ile oynamanız gerektiğini düşünüyorum.


14
for instance, bu bir kelime oyunu mu?
n611x007

4
30 kişi bunun bir kelime oyunu olduğunu düşünmedi :)
Marcello de Sales

2
Desteklenmeyen işlem istisnalarını bizim uyguladığımız yöntemlerden atmak iyi bir uygulamadır. Kaldır () yönteminden desteklenmeyen işlem istisnası atmanın iyi bir fikir olduğunu düşünüyorum!
darshan

2
Üzgünüm @darshan, ama bu çözüm "yineleyicilerin nasıl yazılacağı" ile ilgili ... Odak "mükemmel yazılmış kod yazmak" olsaydı, bu orada olurdu!
Marcello de Sales

hasNext () içinde neden 'arrayList [currentIndex]! = null' kontrolünün gerekli olduğu açık değil. Lütfen birisi açıklayabilir mi?
Bhushan Karmarkar

12

Faktöriyel hesaplamak için Yinelenebilir için iyi bir örnek

FactorialIterable fi = new FactorialIterable(10);
Iterator<Integer> iterator = fi.iterator();
while (iterator.hasNext()){
     System.out.println(iterator.next());
}

Java 1.8 için kısa kod

new FactorialIterable(5).forEach(System.out::println);

Özel Yinelenebilir sınıf

public class FactorialIterable implements Iterable<Integer> {

    private final FactorialIterator factorialIterator;

    public FactorialIterable(Integer value) {
        factorialIterator = new FactorialIterator(value);
    }

    @Override
    public Iterator<Integer> iterator() {
        return factorialIterator;
    }

    @Override
    public void forEach(Consumer<? super Integer> action) {
        Objects.requireNonNull(action);
        Integer last = 0;
        for (Integer t : this) {
            last = t;
        }
        action.accept(last);
    }

}

Özel Yineleyici sınıfı

public class FactorialIterator implements Iterator<Integer> {

    private final Integer mNumber;
    private Integer mPosition;
    private Integer mFactorial;


    public FactorialIterator(Integer number) {
        this.mNumber = number;
        this.mPosition = 1;
        this.mFactorial = 1;
    }

    @Override
    public boolean hasNext() {
        return mPosition <= mNumber;
    }

    @Override
    public Integer next() {
        if (!hasNext())
            return 0;

        mFactorial = mFactorial * mPosition;

        mPosition++;

        return  mFactorial;
    }
}

8

Bu, 'a' ile başlayan öğeler üzerinde yinelenecek şekilde bir yineleyici yazmak için eksiksiz koddur:

import java.util.Iterator;

public class AppDemo {

    public static void main(String args[]) {

        Bag<String> bag1 = new Bag<>();

        bag1.add("alice");
        bag1.add("bob"); 
        bag1.add("abigail");
        bag1.add("charlie"); 

        for (Iterator<String> it1 = bag1.iterator(); it1.hasNext();) {

            String s = it1.next();
            if (s != null)
                System.out.println(s); 
        }
    }
}

Özel Yineleyici sınıfı

import java.util.ArrayList;
import java.util.Iterator;

public class Bag<T> {

    private ArrayList<T> data;

    public Bag() {

        data = new ArrayList<>();
    }

    public void add(T e) {

        data.add(e); 
    }

    public Iterator<T> iterator() {

        return new BagIterator();
    }

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

        private int index; 
        private String str;

        public BagIterator() {

            index = 0;
        }

        @Override
        public boolean hasNext() {

             return index < data.size();  
        }

        @Override
        public T next() {

            str = (String) data.get(index); 
            if (str.startsWith("a"))
                return (T) data.get(index++); 
            index++; 
            return null; 
        }
    } 
}

5

Kendi Yineleyicinizi uygulayabilirsiniz. Yineleyiciniz, List tarafından döndürülen Yineleyiciyi saracak şekilde yapılandırılabilir veya bir imleci tutup List'in get (int indeks) yöntemini kullanabilirsiniz. Filtreleme kriterlerinizi hesaba katmak için Yineleyicinizin sonraki yöntemine VE hasNext yöntemine mantık eklemeniz yeterlidir. Yineleyicinizin kaldırma işlemini destekleyip desteklemeyeceğine de karar vermeniz gerekecektir.


1

İşte sorunun tam cevabı.

import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;

class ListIterator implements Iterator<String>{
    List<String> list;
    int pos = 0;

    public ListIterator(List<String> list) {
        this.list = list;
    }

    @Override
    public boolean hasNext() {
        while(pos < list.size()){
            if (list.get(pos).startsWith("a"))
                return true;
            pos++;
        }
        return false;

    }

    @Override
    public String next() {
        if (hasNext())
            return list.get(pos++);
        throw new NoSuchElementException();
    }
}

public class IteratorTest {

    public static void main(String[] args) {
        List<String> list = Arrays.asList("alice", "bob", "abigail", "charlie");
        ListIterator itr = new ListIterator(list);

        while(itr.hasNext())
            System.out.println(itr.next()); // prints alice, abigail
    }
}
  • ListIterator 'a' ile başlayan öğeleri döndüren dizinin yineleyicisidir.
  • Yinelenebilir bir arabirim uygulamaya gerek yoktur. Ancak bu bir olasılıktır.
  • Bunu jenerik olarak uygulamaya gerek yoktur.
  • HasNext () ve next () sözleşmesini tam olarak karşılar. yani hasNext () hala elemanlar olduğunu söylüyorsa, next () bu elemanları döndürecektir. Ve hasNext () başka öğe olmadığını söylerse, geçerli bir NoSuchElementExceptionistisna döndürür .
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.