イテレータで竹藪を焼く
動機
Iterableの挙動を変えたい。
拡張forはシンタックスが分かりやすいので、もっと使われてもいいと思う。
元ネタ
うろ覚えだがScalaの教科書、Programming in Scala
http://www.amazon.co.jp/Programming-Scala-Comprehensive-Step-step/dp/0981531601
にListにmapする話があったと思う。
方針
Iterableのラッパークラスを作ってimplements Iterableにする。
まずただのラッパークラスをひとつ準備。Iterableと同じ型パラメータ(ここではT)をつけておく。
package iterator; import java.util.Iterator; public class IterableWrapper<T> { protected Iterable<T> iterable; protected Iterator<T> iterator; public IterableWrapper(Iterable<T> iterable) { setIterable(iterable); } public void setIterable(Iterable<T> iterable) { this.iterable = iterable; this.iterator = iterable.iterator(); } }
実装
map (各要素を変換) するIterable
要素AをBに変換して出力するIterableをつくる。
convertValueが変換に使うメソッド。
package iterator; import java.util.Iterator; public abstract class MapIterable<A,B> extends IterableWrapper<A> implements Iterable<B>{ protected abstract B convertValue(A input); public MapIterable(Iterable<A> iterable) { super(iterable); } @Override public Iterator<B> iterator() { return new Iterator<B>(){ @Override public boolean hasNext() { return iterator.hasNext(); } @Override public B next() { //A -> Bの変換 return convertValue(iterator.next()); } @Override public void remove() { iterator.remove(); } }; } }
数字を文字列に変換する例
package iterator; import java.util.ArrayList; import java.util.List; public class Int2StringIterable extends MapIterable<Integer, String>{ public static void main(String[] args) { List<Integer> nums = new ArrayList<Integer>(); //数字を入れます for (int i = 1; i <= 5; i++) { nums.add(i); } Int2StringIterable i2s = new Int2StringIterable(nums); //文字列が出てきます for (String str : i2s) { System.out.println(str); } } public Int2StringIterable(Iterable<Integer> iterable) { super(iterable); } @Override protected String convertValue(Integer input) { if(input == 3){ return input + ""; } if(input == 4){ return input + "がなくて"; } return input + "に努力"; } }
実行結果
1に努力 2に努力 3 4がなくて 5に努力
反転するIterable
一度中身のIterableをたどり、その後逆順にたどるようなIterableをつくる。
たけやぶを入れると焼ける。
package iterator; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.NoSuchElementException; import java.util.Stack; import com.sun.xml.internal.ws.addressing.model.ActionNotSupportedException; /** * Iterableをたどって逆順に戻ってくるIterableなラッパー。 * @author aen * @param <T> Iterableの要素の型 */ public class MirrorIterable<T> extends IterableWrapper<T> implements Iterable<T>{ public static void main(String[] args) { List<Character> chars = new ArrayList<Character>(); String takeyabu = "たけやぶ"; char[] takeyabuc = takeyabu.toCharArray(); //たけやぶをリストに詰めます for (char c : takeyabuc) { chars.add(c); } //ラッパーをかますと MirrorIterable<Character> mirrorNums = new MirrorIterable<Character>(chars); //たけやぶが焼けます。 for (char c : mirrorNums) { System.out.print(c); } System.out.println(); //2回かますと mirrorNums = new MirrorIterable<Character>(chars); MirrorIterable<Character> mirrorNums2 = new MirrorIterable<Character>(mirrorNums); //もっと焼けます。 for (char c : mirrorNums2) { System.out.print(c); } System.out.println(); } /** * たどったオブジェクトを積んでおくスタック。 */ private Stack<T> stack; public MirrorIterable(Iterable<T> iterable) { super(iterable); stack = new Stack<T>(); } @Override public void setIterable(Iterable<T> iterable) { super.setIterable(iterable); stack = new Stack<T>(); } @Override public Iterator<T> iterator() { return new Iterator<T>(){ @Override public boolean hasNext() { return (iterator.hasNext() || !stack.isEmpty()); } @Override public T next() { //まだiteratorがたどれる if(iterator.hasNext()){ T value = iterator.next(); //最後はスタックに積まない if(iterator.hasNext()){ //スタックに履歴を積んでおく stack.push(value); } return value; } //iteratorがたどれなくなったら、スタックから下ろしていく if(!stack.isEmpty()){ return stack.pop(); } throw new NoSuchElementException("no more element"); } @Override public void remove() { throw new ActionNotSupportedException("remove not supported"); } }; } }
実行結果
たけやぶやけた たけやぶやけたけやぶやけた