独自のイテレータをJavaで作成できますか?


103

を含むリストが[alice, bob, abigail, charlie]あり、 'a'で始まる要素を反復するイテレータを作成したい場合、自分で作成できますか?どうやってやるの ?


4
あなたはできる。Iteratorインターフェースを実装する必要があります。
gd1 2011年

確かに、それは単なる通常のインターフェースです。JDO実装のjava.utilのプロキシ。かなり多くのカスタム反復子が含まれます。
bestss

回答:


48

承知しました。イテレータはjava.util.Iteratorインターフェースの単なる実装です。からの既存の反復可能オブジェクト(たとえば、LinkedList)を使用している場合は、java.utilそれをサブクラス化してそのiterator関数をオーバーライドし、独自のオブジェクトを返すか、特別なIteratorインスタンス(標準の反復子)でラップする手段を提供する必要があります。より広く使用されるという利点があります)など。


8
良い答え.... +1ただし、LinkedListをサブクラス化する必要はありません。インターフェイスはコンストラクターについて何も通知しないため、新しいCustomIterator(somelist)でインスタンス化されるCustomIteratorを作成できます。
gd1 2011年

1
@Giacomo:それが「...または標準のイテレータを特別なIteratorインスタンスでラップする手段を提供する...」(そして感謝)の意味です。:-)
TJクラウダー、

195

最適な再利用可能なオプションは、インターフェースIterableを実装し、メソッドiterator()をオーバーライドすることです。

以下は、インターフェースを実装するクラスのようなArrayListの例です。ここでは、メソッドIterator()をオーバーライドしています。

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

このクラスはGenericsを使用してIterableインターフェースを実装します。配列に要素があることを考えると、たとえば「foreach」ループで使用される必要なインスタンスであるイテレータのインスタンスを取得できます。

拡張イテレータを作成せずにイテレータの匿名インスタンスを作成し、currentSizeの値を利用して、配列内を移動できる場所まで確認できます(容量が10の配列を作成したとしましょう。 0および1の要素)。インスタンスには現在の場所の所有者カウンターがあり、現在の値がnullかどうかを確認するhasNext()と、現在のインデックスのインスタンスを返すnext()を操作するだけで済みます。以下は、このAPIの使用例です...

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

必要に応じて、Iteratorインスタンスを使用して同様に反復できます。

// 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のドキュメントはhttp://download.oracle.com/javase/1,5.0/docs/guide/language/foreach.htmlにあります。あなたは私の個人的な練習のGoogleコードでより完全な実装を見ることができます

今、必要なものの効果を得るには、イテレーターにフィルターの概念を組み込む必要があると思います...イテレーターは次の値に依存するため、hasNext()でtrueを返すのは難しいでしょう。たとえば、文字「a」で始まらない値でnext()実装をフィルタリングします。私は、与えられたフィルターの値を持つフィルターされたリストに基づいて、セカンダリInteratorで遊ぶ必要があると思います。


14
for instance、それは駄洒落ですか?
n611x007 2013

4
他の30人はそれをおしゃべりだとは思わなかった:)
Marcello de Sales

2
実装されたメソッドからサポートされていない操作の例外をスローすることは良い習慣です。remove()メソッドからサポートされていない操作の例外をスローするのは良い考えだと思います!
ダルシャン2014年

2
@darshanは申し訳ありませんが、この解決策は「イテレータの記述方法」に関するものです...「完全に記述されたコードを記述する」ことに焦点が当てられていた場合、それはそこにあります!
Marcello de Sales

hasArray()内で 'arrayList [currentIndex]!= null'チェックが必要な理由が明確ではありません。誰かが説明してもらえますか?
Bhushan Karmarkar

12

階乗を計算するIterableの良い例

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

Java 1.8の短いコード

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

カスタム反復可能クラス

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

}

カスタムイテレータクラス

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

これは、 'a'で始まる要素を反復するように反復子を作成するための完全なコードです。

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

カスタムイテレータクラス

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

独自のイテレーターを実装できます。イテレータは、リストから返されたイテレータをラップするように作成することも、カーソルを保持してリストのget(int index)メソッドを使用することもできます。イテレーターの次のメソッドとhasNextメソッドにロジックを追加して、フィルター基準を考慮する必要があります。イテレータが削除操作をサポートするかどうかも決定する必要があります。


1

これが質問に対する完全な回答です。

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」で始まる要素を返す配列のイテレータです。
  • Iterableインターフェースを実装する必要はありません。しかし、それは可能性です。
  • これを包括的に実装する必要はありません。
  • hasNext()とnext()の契約を完全に満たします。つまり、hasNext()がまだ要素があると言った場合、next()はそれらの要素を返します。そして、hasNext()がこれ以上要素がないと言った場合、有効なNoSuchElementException例外を返します。
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.